bitcoinrb 1.7.0 → 1.8.1

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
  SHA256:
3
- metadata.gz: 81a899ff49ba8888d3479e7f0c93c2124098c07c68dfd293349881d724c9393b
4
- data.tar.gz: '052092011357a7abb68ec74bbbd5939b74d75aa83d5561ce088fc80c152b3341'
3
+ metadata.gz: a6e5ff6fa694353e122cd0028354edff2aa877debdc36d368503c25f6277c77f
4
+ data.tar.gz: a6ef9fb214582173d6681dcad6547208b6c606f9d4b82f1c2b3423f388866db1
5
5
  SHA512:
6
- metadata.gz: ce9d912ba951f85c95dd30b29f1f2d0330a168e6fdd119296186fc6e651ba92ab838c90b7d31cf1a99e17def444c6bcb9784eff6ceab0816b210428fbc77b36a
7
- data.tar.gz: bc9f7c2e34f9f47def957b549e5c33f5a4940fb56ad2fb379f717811aedd0b5f1cc4089c0f67ff7ad1363eb9a7d7b4a4ea4405124a06b20a1674d02802720cfe
6
+ metadata.gz: b4b858790060163880d19b8d771383b406facaa755386e7919e8c6d1caa6b7f362eeb611846f13f40b406114cae7d3e100cf4f5cb46adef01e37d40a43c35de6
7
+ data.tar.gz: a4712b529713ad39bebd6f32d9124d2f07d3c77c22482297df550f384b6f3ebf0ee6000958494684a95cc70354f95a22d8361dd686241c2d67c645fcee20ea5c
@@ -19,7 +19,7 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['3.0', '3.1', '3.2', '3.3']
22
+ ruby-version: ['3.1', '3.2', '3.3', '3.4']
23
23
 
24
24
  steps:
25
25
  - uses: actions/checkout@v4
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-3.3.0
1
+ ruby-3.4.1
data/Gemfile CHANGED
@@ -4,3 +4,11 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'parallel_tests'
7
+ gem 'leveldb-native'
8
+ gem 'bundler'
9
+ gem 'rake', '>= 12.3.3'
10
+ gem 'rspec', '~> 3.0'
11
+ gem 'timecop'
12
+ gem 'webmock', '>= 3.11.1'
13
+ gem 'parallel', '>= 1.20.1'
14
+ gem 'csv', '~> 3.3'
data/bitcoinrb.gemspec CHANGED
@@ -26,22 +26,14 @@ Gem::Specification.new do |spec|
26
26
  spec.add_runtime_dependency 'bech32', '>= 1.3.0'
27
27
  spec.add_runtime_dependency 'daemon-spawn'
28
28
  spec.add_runtime_dependency 'thor'
29
- spec.add_runtime_dependency 'ffi'
30
29
  spec.add_runtime_dependency 'leb128', '~> 1.0.0'
31
30
  spec.add_runtime_dependency 'eventmachine_httpserver'
32
31
  spec.add_runtime_dependency 'iniparse'
33
32
  spec.add_runtime_dependency 'siphash'
34
- spec.add_runtime_dependency 'json_pure', '>= 2.3.1'
35
33
  spec.add_runtime_dependency 'bip-schnorr', '>= 0.7.0'
36
34
  spec.add_runtime_dependency 'base32', '>= 0.3.4'
37
-
38
- # for options
39
- spec.add_development_dependency 'leveldb-native'
40
-
41
- spec.add_development_dependency 'bundler'
42
- spec.add_development_dependency 'rake', '>= 12.3.3'
43
- spec.add_development_dependency 'rspec', '~> 3.0'
44
- spec.add_development_dependency 'timecop'
45
- spec.add_development_dependency 'webmock', '>= 3.11.1'
46
- spec.add_development_dependency 'parallel', '>= 1.20.1'
35
+ spec.add_runtime_dependency 'base64', '~> 0.2.0'
36
+ spec.add_runtime_dependency 'observer', '~> 0.1.2'
37
+ spec.add_runtime_dependency 'secp256k1rb', '0.1.1'
38
+ spec.add_runtime_dependency 'logger'
47
39
  end
@@ -19,7 +19,7 @@ module Bitcoin
19
19
  # Decode to public key.
20
20
  # @return [Bitcoin::Key] Decoded public key.
21
21
  def decode
22
- if Bitcoin.secp_impl.is_a?(Bitcoin::Secp256k1::Native)
22
+ if Bitcoin.secp_impl.native?
23
23
  pubkey = Bitcoin.secp_impl.ellswift_decode(key)
24
24
  Bitcoin::Key.new(pubkey: pubkey, key_type: Bitcoin::Key::TYPES[:compressed])
25
25
  else
@@ -131,8 +131,8 @@ module Bitcoin
131
131
  raise ArgumentError, "ellswift_theirs must be a Bitcoin::BIP324::EllSwiftPubkey" unless ellswift_theirs.is_a?(Bitcoin::BIP324::EllSwiftPubkey)
132
132
  raise ArgumentError, "ellswift_ours must be a Bitcoin::BIP324::EllSwiftPubkey" unless ellswift_ours.is_a?(Bitcoin::BIP324::EllSwiftPubkey)
133
133
 
134
- if Bitcoin.secp_impl.is_a?(Bitcoin::Secp256k1::Native)
135
- Bitcoin::Secp256k1::Native.ellswift_ecdh_xonly(ellswift_theirs, ellswift_ours, priv_key, initiating)
134
+ if Bitcoin.secp_impl.native?
135
+ Bitcoin::Secp256k1::Native.ellswift_ecdh_xonly(ellswift_theirs.key, ellswift_ours.key, priv_key, initiating)
136
136
  else
137
137
  ecdh_point_x32 = ellswift_ecdh_xonly(ellswift_theirs, priv_key).htb
138
138
  content = initiating ? ellswift_ours.key + ellswift_theirs.key + ecdh_point_x32 :
@@ -56,6 +56,11 @@ module Bitcoin
56
56
  init('signet')
57
57
  end
58
58
 
59
+ # testnet 4 genesis
60
+ def self.testnet4
61
+ init('testnet4')
62
+ end
63
+
59
64
  def mainnet?
60
65
  network == 'mainnet'
61
66
  end
@@ -72,6 +77,10 @@ module Bitcoin
72
77
  network == 'signet'
73
78
  end
74
79
 
80
+ def testnet4?
81
+ network == 'testnet4'
82
+ end
83
+
75
84
  def genesis_block
76
85
  header = Bitcoin::BlockHeader.new(
77
86
  genesis['version'], genesis['prev_hash'].rhex, genesis['merkle_root'].rhex,
@@ -27,9 +27,13 @@ proof_of_work_limit: 0x1d00ffff
27
27
  dns_seeds:
28
28
  - "seed.bitcoin.sipa.be"
29
29
  - "dnsseed.bluematt.me"
30
- - "dnsseed.bitcoin.dashjr.org"
31
- - "seed.bitcoinstats.com"
30
+ - "dnsseed.bitcoin.dashjr-list-of-p2p-nodes.us"
32
31
  - "seed.bitcoin.jonasschnelli.ch"
32
+ - "seed.btc.petertodd.net"
33
+ - "seed.bitcoin.sprovoost.nl"
34
+ - "dnsseed.emzy.de"
35
+ - "seed.bitcoin.wiz.biz"
36
+ - "seed.mainnet.achownodes.xyz"
33
37
  genesis:
34
38
  hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
35
39
  merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
@@ -22,8 +22,7 @@ retarget_interval: 2016
22
22
  retarget_time: 1209600 # 2 weeks
23
23
  target_spacing: 600 # block interval
24
24
  max_money: 21000000
25
- bip34_height: 0
26
- genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
25
+ bip34_height: 1
27
26
  proof_of_work_limit: 0x207fffff
28
27
  dns_seeds:
29
28
  genesis:
@@ -22,12 +22,11 @@ retarget_interval: 2016
22
22
  retarget_time: 1209600 # 2 weeks
23
23
  target_spacing: 600 # block interval
24
24
  max_money: 21000000
25
- bip34_height: 227931
26
- genesis_hash: "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
25
+ bip34_height: 1
27
26
  proof_of_work_limit: 0x1d00ffff
28
27
  dns_seeds:
29
- - "178.128.221.177"
30
- - "2a01:7c8:d005:390::5"
28
+ - "seed.signet.bitcoin.sprovoost.nl"
29
+ - "seed.signet.achownodes.xyz"
31
30
  genesis:
32
31
  hash: "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
33
32
  merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
@@ -22,14 +22,14 @@ retarget_interval: 2016
22
22
  retarget_time: 1209600 # 2 weeks
23
23
  target_spacing: 600 # block interval
24
24
  max_money: 21000000
25
- bip34_height: 227931
26
- genesis_hash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
25
+ bip34_height: 21111
27
26
  proof_of_work_limit: 0x1d00ffff
28
27
  dns_seeds:
29
28
  - "testnet-seed.bitcoin.jonasschnelli.ch"
30
- - "seed.tbtc.petertodd.org"
29
+ - "seed.tbtc.petertodd.net"
30
+ - "seed.testnet.bitcoin.sprovoost.nl"
31
31
  - "testnet-seed.bluematt.me"
32
- - "testnet-seed.bitcoin.schildbach.de"
32
+ - "seed.testnet.achownodes.xyz"
33
33
  genesis:
34
34
  hash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
35
35
  merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
@@ -0,0 +1,38 @@
1
+ --- !ruby/object:Bitcoin::ChainParams
2
+ network: "testnet4"
3
+ magic_head: "1c163f28"
4
+ message_magic: "Bitcoin Signed Message:\n"
5
+ address_version: "6f"
6
+ p2sh_version: "c4"
7
+ bech32_hrp: 'tb'
8
+ privkey_version: "ef"
9
+ extended_privkey_version: "04358394"
10
+ extended_pubkey_version: "043587cf"
11
+ bip49_pubkey_p2wpkh_p2sh_version: "044a5262"
12
+ bip49_pubkey_p2wsh_p2sh_version: "024289ef"
13
+ bip49_privkey_p2wpkh_p2sh_version: "044a4e28"
14
+ bip49_privkey_p2wsh_p2sh_version: "024285b5"
15
+ bip84_pubkey_p2wpkh_version: "045f1cf6"
16
+ bip84_pubkey_p2wsh_version: "02575483"
17
+ bip84_privkey_p2wpkh_version: "045f18bc"
18
+ bip84_privkey_p2wsh_version: "02575048"
19
+ default_port: 48333
20
+ protocol_version: 70013
21
+ retarget_interval: 2016
22
+ retarget_time: 1209600 # 2 weeks
23
+ target_spacing: 600 # block interval
24
+ max_money: 21000000
25
+ bip34_height: 1
26
+ proof_of_work_limit: 0x1d00ffff
27
+ dns_seeds:
28
+ - "seed.testnet4.bitcoin.sprovoost.nl"
29
+ - "seed.testnet4.wiz.biz"
30
+ genesis:
31
+ hash: "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043"
32
+ merkle_root: "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e"
33
+ time: 1714777860
34
+ nonce: 393743547
35
+ bits: 0x1d00ffff
36
+ version: 1
37
+ prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
38
+ bip44_coin_type: 1
data/lib/bitcoin/ext.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Bitcoin
2
2
  module Ext
3
- autoload :JsonParser, 'bitcoin/ext/json_parser'
4
3
  autoload :ArrayExt, 'bitcoin/ext/array_ext'
5
4
  autoload :ObjectExt, 'bitcoin/ext/object_ext'
6
5
  end
data/lib/bitcoin/key.rb CHANGED
@@ -146,11 +146,8 @@ module Bitcoin
146
146
  # @return [Bitcoin::Key] Recovered public key.
147
147
  def self.recover_compact(data, signature)
148
148
  rec_id = signature.unpack1('C')
149
- rec = (rec_id - Bitcoin::Key::COMPACT_SIG_HEADER_BYTE) & 3
150
- raise ArgumentError, 'Invalid signature parameter' if rec < 0 || rec > 3
151
-
152
149
  compressed = (rec_id - Bitcoin::Key::COMPACT_SIG_HEADER_BYTE) & 4 != 0
153
- Bitcoin.secp_impl.recover_compact(data, signature, rec, compressed)
150
+ Bitcoin.secp_impl.recover_compact(data, signature, compressed)
154
151
  end
155
152
 
156
153
  # verify signature using public key
@@ -349,7 +346,7 @@ module Bitcoin
349
346
  # @raise ArgumentError If ent32 does not 32 bytes.
350
347
  def create_ell_pubkey
351
348
  raise ArgumentError, "private_key required." unless priv_key
352
- if secp256k1_module.is_a?(Bitcoin::Secp256k1::Native)
349
+ if secp256k1_module.native?
353
350
  Bitcoin::BIP324::EllSwiftPubkey.new(secp256k1_module.ellswift_create(priv_key))
354
351
  else
355
352
  Bitcoin::BIP324::EllSwiftPubkey.new(Bitcoin::BIP324.xelligatorswift(xonly_pubkey))
@@ -62,13 +62,23 @@ module Bitcoin
62
62
  pubkey = Bitcoin::Key.recover_compact(message_hash(message, prefix: prefix, legacy: true), sig)
63
63
  return false unless pubkey
64
64
  pubkey.to_p2pkh == address
65
- rescue RuntimeError
66
- return false
65
+ rescue Exception
66
+ false
67
67
  end
68
68
  elsif addr_script.witness_program?
69
69
  # BIP322 verification
70
- tx = to_sign_tx(message_hash(message, prefix: prefix, legacy: false), address)
71
- tx.in[0].script_witness = Bitcoin::ScriptWitness.parse_from_payload(sig)
70
+ digest = message_hash(message, prefix: prefix, legacy: false)
71
+ begin
72
+ # Full
73
+ tx = Bitcoin::Tx.parse_from_payload(sig)
74
+ validate_to_sign_tx!(tx)
75
+ to_spend = to_spend_tx(digest, address)
76
+ return false unless tx.in[0].out_point.tx_hash == to_spend.tx_hash
77
+ rescue Exception
78
+ # Simple
79
+ tx = to_sign_tx(digest, address)
80
+ tx.in[0].script_witness = Bitcoin::ScriptWitness.parse_from_payload(sig)
81
+ end
72
82
  script_pubkey = Bitcoin::Script.parse_from_addr(address)
73
83
  tx_out = Bitcoin::TxOut.new(script_pubkey: script_pubkey)
74
84
  flags = Bitcoin::STANDARD_SCRIPT_VERIFY_FLAGS
@@ -99,6 +109,14 @@ module Bitcoin
99
109
  end
100
110
  end
101
111
 
112
+ def validate_to_sign_tx!(tx)
113
+ raise ArgumentError, "Multiple inputs (proof of funds) are not supported." unless tx.in.length == 1
114
+ raise ArgumentError, "vin[0].prevout.n must be 0." unless tx.in[0].out_point.index == 0
115
+ raise ArgumentError, "Multiple outputs are not supported." unless tx.out.length == 1
116
+ raise ArgumentError, "vout[0].nValue must be 0." unless tx.out[0].value == 0
117
+ raise ArgumentError, "vout[0].scriptPubKey must be OP_RETURN." unless tx.out[0].script_pubkey == Bitcoin::Script.new << Bitcoin::Opcodes::OP_RETURN
118
+ end
119
+
102
120
  def to_spend_tx(digest, addr)
103
121
  validate_address!(addr)
104
122
  message_challenge = Bitcoin::Script.parse_from_addr(addr)
@@ -124,5 +142,6 @@ module Bitcoin
124
142
 
125
143
  private_class_method :validate_address!
126
144
  private_class_method :validate_format!
145
+ private_class_method :validate_to_sign_tx!
127
146
  end
128
147
  end
data/lib/bitcoin/psbt.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'base64'
2
-
3
1
  module Bitcoin
4
2
 
5
3
  module PSBT
@@ -62,7 +62,8 @@ module Bitcoin
62
62
  request.body = data.to_json
63
63
  response = http.request(request)
64
64
  body = response.body
65
- response = Bitcoin::Ext::JsonParser.new(body.gsub(/\\u([\da-fA-F]{4})/) { [$1].pack('H*').unpack('n*').pack('U*').encode('ISO-8859-1').force_encoding('UTF-8') }).parse
65
+ json_data = JSON.parse(body.gsub(/\\u([\da-fA-F]{4})/) { [$1].pack('H*').unpack('n*').pack('U*').encode('ISO-8859-1').force_encoding('UTF-8') })
66
+ response = convert_floats_to_strings(json_data)
66
67
  raise response['error'].to_json if response['error']
67
68
  response['result']
68
69
  end
@@ -77,6 +78,19 @@ module Bitcoin
77
78
  end
78
79
  end
79
80
 
81
+ # Convert float value
82
+ def convert_floats_to_strings(obj)
83
+ case obj
84
+ when Float
85
+ obj.to_s
86
+ when Hash
87
+ obj.transform_values { |v| convert_floats_to_strings(v) }
88
+ when Array
89
+ obj.map { |item| convert_floats_to_strings(item) }
90
+ else
91
+ obj
92
+ end
93
+ end
80
94
  end
81
95
  end
82
96
  end
@@ -37,7 +37,7 @@ module Bitcoin
37
37
 
38
38
  # check schnorr signature.
39
39
  # @param [String] sig schnorr signature with hex format.
40
- # @param [String] pubkey a public key with hex fromat.
40
+ # @param [String] pubkey a public key with hex format.
41
41
  # @param [Symbol] sig_version whether :taproot or :tapscript
42
42
  # @return [Boolean] verification result
43
43
  def check_schnorr_sig(sig, pubkey, sig_version, opts = {})
@@ -1,5 +1,6 @@
1
1
  # Porting part of the code from bitcoin-ruby. see the license.
2
2
  # https://github.com/lian/bitcoin-ruby/blob/master/COPYING
3
+ require 'secp256k1'
3
4
 
4
5
  module Bitcoin
5
6
  module Secp256k1
@@ -10,91 +11,15 @@ module Bitcoin
10
11
  # for linux, ENV['SECP256K1_LIB_PATH'] = '/usr/local/lib/libsecp256k1.so' or '/usr/lib64/libsecp256k1.so'
11
12
  # for mac,
12
13
  module Native
13
- include ::FFI::Library
14
- extend self
15
-
16
- SECP256K1_FLAGS_TYPE_MASK = ((1 << 8) - 1)
17
- SECP256K1_FLAGS_TYPE_CONTEXT = (1 << 0)
18
- SECP256K1_FLAGS_TYPE_COMPRESSION = (1 << 1)
19
-
20
- SECP256K1_FLAGS_BIT_CONTEXT_VERIFY = (1 << 8)
21
- SECP256K1_FLAGS_BIT_CONTEXT_SIGN = (1 << 9)
22
- SECP256K1_FLAGS_BIT_COMPRESSION = (1 << 8)
23
-
24
- # Flags to pass to secp256k1_context_create.
25
- SECP256K1_CONTEXT_VERIFY = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
26
- SECP256K1_CONTEXT_SIGN = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
27
-
28
- # Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export.
29
- SECP256K1_EC_COMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
30
- SECP256K1_EC_UNCOMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION)
31
14
 
32
15
  module_function
33
16
 
34
- def init
35
- raise 'secp256k1 library dose not found.' unless File.exist?(ENV['SECP256K1_LIB_PATH'])
36
- ffi_lib(ENV['SECP256K1_LIB_PATH'])
37
- load_functions
38
- end
39
-
40
- def load_functions
41
- attach_function(:secp256k1_context_create, [:uint], :pointer)
42
- attach_function(:secp256k1_context_destroy, [:pointer], :void)
43
- attach_function(:secp256k1_context_randomize, [:pointer, :pointer], :int)
44
- attach_function(:secp256k1_ec_pubkey_create, [:pointer, :pointer, :pointer], :int)
45
- attach_function(:secp256k1_ec_seckey_verify, [:pointer, :pointer], :int)
46
- attach_function(:secp256k1_ecdsa_sign, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int)
47
- attach_function(:secp256k1_ec_pubkey_serialize, [:pointer, :pointer, :pointer, :pointer, :uint], :int)
48
- attach_function(:secp256k1_ecdsa_signature_serialize_der, [:pointer, :pointer, :pointer, :pointer], :int)
49
- attach_function(:secp256k1_ec_pubkey_parse, [:pointer, :pointer, :pointer, :size_t], :int)
50
- attach_function(:secp256k1_ecdsa_signature_parse_der, [:pointer, :pointer, :pointer, :size_t], :int)
51
- attach_function(:secp256k1_ecdsa_signature_normalize, [:pointer, :pointer, :pointer], :int)
52
- attach_function(:secp256k1_ecdsa_verify, [:pointer, :pointer, :pointer, :pointer], :int)
53
- attach_function(:secp256k1_schnorrsig_sign32, [:pointer, :pointer, :pointer, :pointer, :pointer], :int)
54
- attach_function(:secp256k1_schnorrsig_verify, [:pointer, :pointer, :pointer, :size_t, :pointer], :int)
55
- attach_function(:secp256k1_keypair_create, [:pointer, :pointer, :pointer], :int)
56
- attach_function(:secp256k1_xonly_pubkey_parse, [:pointer, :pointer, :pointer], :int)
57
- attach_function(:secp256k1_ecdsa_sign_recoverable, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int)
58
- attach_function(:secp256k1_ecdsa_recoverable_signature_serialize_compact, [:pointer, :pointer, :pointer, :pointer], :int)
59
- attach_function(:secp256k1_ecdsa_recover, [:pointer, :pointer, :pointer, :pointer], :int)
60
- attach_function(:secp256k1_ecdsa_recoverable_signature_parse_compact, [:pointer, :pointer, :pointer, :int], :int)
61
- attach_function(:secp256k1_ellswift_decode, [:pointer, :pointer, :pointer], :int)
62
- attach_function(:secp256k1_ellswift_create, [:pointer, :pointer, :pointer, :pointer], :int)
63
- # Define function pointer
64
- callback(:secp256k1_ellswift_xdh_hash_function, [:pointer, :pointer, :pointer, :pointer, :pointer], :int)
65
- attach_variable(:secp256k1_ellswift_xdh_hash_function_bip324, :secp256k1_ellswift_xdh_hash_function)
66
- attach_function(:secp256k1_ellswift_xdh, [:pointer, :pointer, :pointer, :pointer, :pointer, :int, :pointer, :pointer], :int)
67
- end
68
-
69
- def with_context(flags: (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN))
70
- init
71
- begin
72
- context = secp256k1_context_create(flags)
73
- ret, tries, max = 0, 0, 20
74
- while ret != 1
75
- raise 'secp256k1_context_randomize failed.' if tries >= max
76
- tries += 1
77
- ret = secp256k1_context_randomize(context, FFI::MemoryPointer.from_string(SecureRandom.random_bytes(32)))
78
- end
79
- yield(context) if block_given?
80
- ensure
81
- secp256k1_context_destroy(context)
82
- end
83
- end
17
+ extend ::Secp256k1
84
18
 
85
- # generate ec private key and public key
86
- def generate_key_pair(compressed: true)
87
- with_context do |context|
88
- ret, tries, max = 0, 0, 20
89
- while ret != 1
90
- raise 'secp256k1_ec_seckey_verify in generate_key_pair failed.' if tries >= max
91
- tries += 1
92
- priv_key = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
93
- ret = secp256k1_ec_seckey_verify(context, priv_key)
94
- end
95
- private_key = priv_key.read_string(32).bth
96
- [private_key , generate_pubkey_in_context(context, private_key, compressed: compressed) ]
97
- end
19
+ # Whether this module is native c wrapper or not?
20
+ # @return [Boolean]
21
+ def native?
22
+ true
98
23
  end
99
24
 
100
25
  # generate bitcoin key object
@@ -103,295 +28,76 @@ module Bitcoin
103
28
  Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
104
29
  end
105
30
 
106
- def generate_pubkey(priv_key, compressed: true)
107
- with_context do |context|
108
- generate_pubkey_in_context(context, priv_key, compressed: compressed)
109
- end
110
- end
111
-
112
- # sign data.
113
- # @param [String] data a data to be signed with binary format
114
- # @param [String] privkey a private key with hex format using sign
115
- # @param [String] extra_entropy a extra entropy with binary format for rfc6979
116
- # @param [Symbol] algo signature algorithm. ecdsa(default) or schnorr.
117
- # @return [String] signature data with binary format
118
- def sign_data(data, privkey, extra_entropy = nil, algo: :ecdsa)
119
- case algo
120
- when :ecdsa
121
- sign_ecdsa(data, privkey, extra_entropy)
122
- when :schnorr
123
- sign_schnorr(data, privkey, extra_entropy)
124
- else
125
- nil
126
- end
127
- end
128
-
129
31
  # Sign data with compact format.
130
32
  # @param [String] data a data to be signed with binary format
131
33
  # @param [String] privkey a private key using sign with hex format
132
34
  # @return [Array[signature, recovery id]]
133
35
  def sign_compact(data, privkey)
134
- with_context do |context|
135
- sig = FFI::MemoryPointer.new(:uchar, 65)
136
- hash =FFI::MemoryPointer.new(:uchar, data.bytesize).put_bytes(0, data)
137
- priv_key = privkey.htb
138
- sec_key = FFI::MemoryPointer.new(:uchar, priv_key.bytesize).put_bytes(0, priv_key)
139
- result = secp256k1_ecdsa_sign_recoverable(context, sig, hash, sec_key, nil, nil)
140
- raise 'secp256k1_ecdsa_sign_recoverable failed.' if result == 0
141
-
142
- output = FFI::MemoryPointer.new(:uchar, 64)
143
- rec = FFI::MemoryPointer.new(:uint64)
144
- result = secp256k1_ecdsa_recoverable_signature_serialize_compact(context, output, rec, sig)
145
- raise 'secp256k1_ecdsa_recoverable_signature_serialize_compact failed.' unless result == 1
146
-
147
- raw_sig = output.read_string(64)
148
- [ECDSA::Signature.new(raw_sig[0...32].bti, raw_sig[32..-1].bti), rec.read(:int)]
149
- end
36
+ sig, rec_id = sign_recoverable(data, privkey)
37
+ [ECDSA::Signature.new(sig[0...64].to_i(16), sig[64..-1].to_i(16)), rec_id]
150
38
  end
151
39
 
152
40
  # Recover public key from compact signature.
153
41
  # @param [String] data message digest using signature.
154
- # @param [String] signature signature with binary format.
155
- # @param [Integer] rec recovery id.
42
+ # @param [String] signature signature with binary format(65 bytes).
156
43
  # @param [Boolean] compressed whether compressed public key or not.
157
44
  # @return [Bitcoin::Key] Recovered public key.
158
- def recover_compact(data, signature, rec, compressed)
159
- with_context do |context|
160
- sig = FFI::MemoryPointer.new(:uchar, 65)
161
- input = FFI::MemoryPointer.new(:uchar, 64).put_bytes(0, signature[1..-1])
162
- result = secp256k1_ecdsa_recoverable_signature_parse_compact(context, sig, input, rec)
163
- raise 'secp256k1_ecdsa_recoverable_signature_parse_compact failed.' unless result == 1
164
-
165
- pubkey = FFI::MemoryPointer.new(:uchar, 64)
166
- msg = FFI::MemoryPointer.new(:uchar, data.bytesize).put_bytes(0, data)
167
- result = secp256k1_ecdsa_recover(context, pubkey, sig, msg)
168
- raise 'secp256k1_ecdsa_recover failed.' unless result == 1
169
-
170
- pubkey = serialize_pubkey_internal(context, pubkey.read_string(64), compressed)
171
- Bitcoin::Key.new(pubkey: pubkey, compressed: compressed)
172
- end
45
+ def recover_compact(data, signature, compressed)
46
+ pubkey = recover(data, signature, compressed)
47
+ Bitcoin::Key.new(pubkey: pubkey, compressed: compressed)
173
48
  end
174
49
 
175
- # verify signature
176
- # @param [String] data a data with binary format.
177
- # @param [String] sig signature data with binary format
178
- # @param [String] pubkey a public key with hex format using verify.
179
- # # @param [Symbol] algo signature algorithm. ecdsa(default) or schnorr.
180
- # @return [Boolean] verification result.
181
- def verify_sig(data, sig, pubkey, algo: :ecdsa)
50
+ # Sign to data.
51
+ # @param [String] data The 32-byte message hash being signed with binary format.
52
+ # @param [String] private_key a private key with hex format using sign.
53
+ # @param [String] extra_entropy a extra entropy with binary format for rfc6979.
54
+ # @param [Symbol] algo signature algorithm. ecdsa(default) or schnorr.
55
+ # @return [String] signature data with binary format. If unsupported algorithm specified, return nil.
56
+ # @raise [ArgumentError] If invalid arguments specified.
57
+ def sign_data(data, private_key, extra_entropy = nil, algo: :ecdsa)
182
58
  case algo
183
59
  when :ecdsa
184
- verify_ecdsa(data, sig, pubkey)
60
+ begin
61
+ sign_ecdsa(data, private_key, extra_entropy)
62
+ rescue ArgumentError
63
+ false
64
+ end
185
65
  when :schnorr
186
- verify_schnorr(data, sig, pubkey)
66
+ begin
67
+ sign_schnorr(data, private_key, extra_entropy)
68
+ rescue ArgumentError
69
+ false
70
+ end
187
71
  else
188
- false
189
- end
190
- end
191
-
192
- # # validate whether this is a valid public key (more expensive than IsValid())
193
- # @param [String] pub_key public key with hex format.
194
- # @param [Boolean] allow_hybrid whether support hybrid public key.
195
- # @return [Boolean] If valid public key return true, otherwise false.
196
- def parse_ec_pubkey?(pub_key, allow_hybrid = false)
197
- pub_key = pub_key.htb
198
- return false if !allow_hybrid && ![0x02, 0x03, 0x04].include?(pub_key[0].ord)
199
- with_context do |context|
200
- pubkey = FFI::MemoryPointer.new(:uchar, pub_key.bytesize).put_bytes(0, pub_key)
201
- internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
202
- result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pub_key.bytesize)
203
- result == 1
72
+ raise ArgumentError, "unknown algo: #{algo}"
204
73
  end
205
74
  end
206
75
 
207
- # Create key pair data from private key.
208
- # @param [String] priv_key with hex format
209
- # @return [String] key pair data with hex format. data = private key(32 bytes) | public key(64 bytes).
210
- def create_keypair(priv_key)
211
- with_context do |context|
212
- priv_key = priv_key.htb
213
- secret = FFI::MemoryPointer.new(:uchar, priv_key.bytesize).put_bytes(0, priv_key)
214
- raise 'priv_key is invalid.' unless secp256k1_ec_seckey_verify(context, secret)
215
- keypair = FFI::MemoryPointer.new(:uchar, 96)
216
- raise 'priv_key is invalid.' unless secp256k1_keypair_create(context, keypair, secret) == 1
217
- keypair.read_string(96).bth
218
- end
219
- end
220
-
221
- # Check whether valid x-only public key or not.
222
- # @param [String] pub_key x-only public key with hex format(32 bytes).
223
- # @return [Boolean] result.
224
- def valid_xonly_pubkey?(pub_key)
225
- begin
226
- full_pubkey_from_xonly_pubkey(pub_key)
227
- rescue Exception
228
- return false
229
- end
230
- true
231
- end
232
-
233
- # Decode ellswift public key.
234
- # @param [String] ell_key ElligatorSwift key with binary format.
235
- # @return [String] Decoded public key with hex format
236
- def ellswift_decode(ell_key)
237
- with_context do |context|
238
- ell64 = FFI::MemoryPointer.new(:uchar, ell_key.bytesize).put_bytes(0, ell_key)
239
- internal = FFI::MemoryPointer.new(:uchar, 64)
240
- result = secp256k1_ellswift_decode(context, internal, ell64)
241
- raise ArgumentError, 'Decode failed.' unless result == 1
242
- serialize_pubkey_internal(context, internal, true)
243
- end
244
- end
245
-
246
- # Compute an ElligatorSwift public key for a secret key.
247
- # @param [String] priv_key private key with hex format
248
- # @return [String] ElligatorSwift public key with hex format.
249
- def ellswift_create(priv_key)
250
- with_context(flags: SECP256K1_CONTEXT_SIGN) do |context|
251
- ell64 = FFI::MemoryPointer.new(:uchar, 64)
252
- seckey32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, priv_key.htb)
253
- result = secp256k1_ellswift_create(context, ell64, seckey32, nil)
254
- raise ArgumentError, 'Failed to create ElligatorSwift public key.' unless result == 1
255
- ell64.read_string(64).bth
256
- end
257
- end
258
-
259
- # Compute X coordinate of shared ECDH point between elswift pubkey and privkey.
260
- # @param [Bitcoin::BIP324::EllSwiftPubkey] their_ell_pubkey Their EllSwift public key.
261
- # @param [Bitcoin::BIP324::EllSwiftPubkey] our_ell_pubkey Our EllSwift public key.
262
- # @param [String] priv_key private key with hex format.
263
- # @param [Boolean] initiating Whether your initiator or not.
264
- # @return [String] x coordinate with hex format.
265
- def ellswift_ecdh_xonly(their_ell_pubkey, our_ell_pubkey, priv_key, initiating)
266
- with_context(flags: SECP256K1_CONTEXT_SIGN) do |context|
267
- output = FFI::MemoryPointer.new(:uchar, 32)
268
- our_ell_ptr = FFI::MemoryPointer.new(:uchar, 64).put_bytes(0, our_ell_pubkey.key)
269
- their_ell_ptr = FFI::MemoryPointer.new(:uchar, 64).put_bytes(0, their_ell_pubkey.key)
270
- seckey32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, priv_key.htb)
271
- hashfp = secp256k1_ellswift_xdh_hash_function_bip324
272
- result = secp256k1_ellswift_xdh(context, output,
273
- initiating ? our_ell_ptr : their_ell_ptr,
274
- initiating ? their_ell_ptr : our_ell_ptr,
275
- seckey32,
276
- initiating ? 0 : 1,
277
- hashfp, nil)
278
- raise ArgumentError, "secret was invalid or hashfp returned 0" unless result == 1
279
- output.read_string(32).bth
280
- end
281
- end
282
-
283
- private
284
-
285
- # Calculate full public key(64 bytes) from public key(32 bytes).
286
- # @param [String] pub_key x-only public key with hex format(32 bytes).
287
- # @return [String] x-only public key with hex format(64 bytes).
288
- def full_pubkey_from_xonly_pubkey(pub_key)
289
- with_context do |context|
290
- pubkey = pub_key.htb
291
- raise ArgumentError, "Pubkey size must be #{X_ONLY_PUBKEY_SIZE} bytes." unless pubkey.bytesize == X_ONLY_PUBKEY_SIZE
292
- xonly_pubkey = FFI::MemoryPointer.new(:uchar, pubkey.bytesize).put_bytes(0, pubkey)
293
- full_pubkey = FFI::MemoryPointer.new(:uchar, 64)
294
- raise ArgumentError, 'An invalid public key was specified.' unless secp256k1_xonly_pubkey_parse(context, full_pubkey, xonly_pubkey) == 1
295
- full_pubkey.read_string(64).bth
296
- end
297
- end
298
-
299
- def generate_pubkey_in_context(context, privkey, compressed: true)
300
- internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
301
- result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
302
- raise 'error creating pubkey' unless result
303
- serialize_pubkey_internal(context, internal_pubkey, compressed)
304
- end
305
-
306
- def sign_ecdsa(data, privkey, extra_entropy)
307
- with_context do |context|
308
- secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
309
- raise 'priv_key is invalid' unless secp256k1_ec_seckey_verify(context, secret)
310
-
311
- internal_signature = FFI::MemoryPointer.new(:uchar, 64)
312
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
313
- entropy = extra_entropy ? FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, extra_entropy) : nil
314
-
315
- ret, tries, max = 0, 0, 20
316
-
317
- while ret != 1
318
- raise 'secp256k1_ecdsa_sign failed.' if tries >= max
319
- tries += 1
320
- ret = secp256k1_ecdsa_sign(context, internal_signature, msg32, secret, nil, entropy)
76
+ # Verify signature.
77
+ # @param [String] data The 32-byte message hash assumed to be signed.
78
+ # @param [String] signature signature data with binary format
79
+ # @param [String] pubkey a public key with hex format using verify.
80
+ # @param [Symbol] algo signature algorithm. ecdsa(default) or schnorr.
81
+ # @return [Boolean] verification result.
82
+ # @raise [ArgumentError] If invalid arguments specified.
83
+ def verify_sig(data, signature, pubkey, algo: :ecdsa)
84
+ case algo
85
+ when :ecdsa
86
+ begin
87
+ verify_ecdsa(data, signature, pubkey)
88
+ rescue ArgumentError
89
+ false
321
90
  end
322
-
323
- signature = FFI::MemoryPointer.new(:uchar, 72)
324
- signature_len = FFI::MemoryPointer.new(:uint64).put_uint64(0, 72)
325
- result = secp256k1_ecdsa_signature_serialize_der(context, signature, signature_len, internal_signature)
326
- raise 'secp256k1_ecdsa_signature_serialize_der failed' unless result
327
-
328
- signature.read_string(signature_len.read_uint64)
329
- end
330
- end
331
-
332
- def sign_schnorr(data, privkey, aux_rand = nil)
333
- with_context do |context|
334
- keypair = create_keypair(privkey).htb
335
- keypair = FFI::MemoryPointer.new(:uchar, 96).put_bytes(0, keypair)
336
- signature = FFI::MemoryPointer.new(:uchar, 64)
337
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
338
- aux_rand = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, aux_rand) if aux_rand
339
- raise 'Failed to generate schnorr signature.' unless secp256k1_schnorrsig_sign32(context, signature, msg32, keypair, aux_rand) == 1
340
- signature.read_string(64)
341
- end
342
- end
343
-
344
- def verify_ecdsa(data, sig, pubkey)
345
- with_context do |context|
346
- return false if data.bytesize == 0
347
- pubkey = pubkey.htb
348
- pubkey = FFI::MemoryPointer.new(:uchar, pubkey.bytesize).put_bytes(0, pubkey)
349
- internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
350
- result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pubkey.size)
351
- return false unless result
352
-
353
- signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
354
- internal_signature = FFI::MemoryPointer.new(:uchar, 64)
355
- result = secp256k1_ecdsa_signature_parse_der(context, internal_signature, signature, signature.size)
356
- return false unless result
357
-
358
- # libsecp256k1's ECDSA verification requires lower-S signatures, which have not historically been enforced in Bitcoin, so normalize them first.
359
- secp256k1_ecdsa_signature_normalize(context, internal_signature, internal_signature)
360
-
361
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
362
- result = secp256k1_ecdsa_verify(context, internal_signature, msg32, internal_pubkey)
363
-
364
- result == 1
365
- end
366
- end
367
-
368
- def verify_schnorr(data, sig, pubkey)
369
- with_context do |context|
370
- return false if data.bytesize == 0
371
- pubkey = full_pubkey_from_xonly_pubkey(pubkey).htb
372
- xonly_pubkey = FFI::MemoryPointer.new(:uchar, pubkey.bytesize).put_bytes(0, pubkey)
373
- signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
374
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
375
- result = secp256k1_schnorrsig_verify(context, signature, msg32, 32, xonly_pubkey)
376
- result == 1
91
+ when :schnorr
92
+ begin
93
+ verify_schnorr(data, signature, pubkey)
94
+ rescue ArgumentError
95
+ false
96
+ end
97
+ else
98
+ raise ArgumentError, "unknown algo: #{algo}"
377
99
  end
378
100
  end
379
-
380
- # Serialize public key.
381
- def serialize_pubkey_internal(context, pubkey_input, compressed)
382
- pubkey = FFI::MemoryPointer.new(:uchar, 65)
383
- pubkey_len = FFI::MemoryPointer.new(:uint64)
384
- result = if compressed
385
- pubkey_len.put_uint64(0, 33)
386
- secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, pubkey_input, SECP256K1_EC_COMPRESSED)
387
- else
388
- pubkey_len.put_uint64(0, 65)
389
- secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, pubkey_input, SECP256K1_EC_UNCOMPRESSED)
390
- end
391
- raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
392
- pubkey.read_string(pubkey_len.read_uint64).bth
393
- end
394
-
395
101
  end
396
102
  end
397
103
  end
@@ -9,6 +9,13 @@ module Bitcoin
9
9
  module Ruby
10
10
 
11
11
  module_function
12
+ extend Schnorr::Util
13
+
14
+ # Whether this module is native c wrapper or not?
15
+ # @return [Boolean]
16
+ def native?
17
+ false
18
+ end
12
19
 
13
20
  # generate ec private key and public key
14
21
  def generate_key_pair(compressed: true)
@@ -72,11 +79,20 @@ module Bitcoin
72
79
 
73
80
  # Recover public key from compact signature.
74
81
  # @param [String] data message digest using signature.
75
- # @param [String] signature signature with binary format.
76
- # @param [Integer] rec recovery id.
82
+ # @param [String] signature signature with binary format(65 bytes).
77
83
  # @param [Boolean] compressed whether compressed public key or not.
78
84
  # @return [Bitcoin::Key] Recovered public key.
79
- def recover_compact(data, signature, rec, compressed)
85
+ # @raise [ArgumentError] If invalid arguments specified.
86
+ def recover_compact(data, signature, compressed)
87
+ raise ArgumentError, "data must be String." unless data.is_a?(String)
88
+ raise ArgumentError, "signature must be String." unless signature.is_a?(String)
89
+ signature = hex2bin(signature)
90
+ raise ArgumentError, "signature must be 64 bytes." unless signature.bytesize == 65
91
+ data = hex2bin(data)
92
+ raise ArgumentError, "data must be 32 bytes." unless data.bytesize == 32
93
+ rec = (signature[0].ord - 0x1b) & 3
94
+ raise ArgumentError, "rec must be between 0 and 3." if rec < 0 || rec > 3
95
+
80
96
  group = Bitcoin::Secp256k1::GROUP
81
97
  r = ECDSA::Format::IntegerOctetString.decode(signature[1...33])
82
98
  s = ECDSA::Format::IntegerOctetString.decode(signature[33..-1])
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "1.7.0"
2
+ VERSION = "1.8.1"
3
3
  end
data/lib/bitcoin.rb CHANGED
@@ -7,7 +7,7 @@ require 'schnorr'
7
7
  require 'securerandom'
8
8
  require 'json'
9
9
  require 'bech32'
10
- require 'ffi'
10
+ require 'base64'
11
11
  require 'observer'
12
12
  require 'tmpdir'
13
13
  require_relative 'openassets'
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoinrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-08-17 00:00:00.000000000 Z
10
+ date: 2025-03-18 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: ecdsa_ext
@@ -94,20 +93,6 @@ dependencies:
94
93
  - - ">="
95
94
  - !ruby/object:Gem::Version
96
95
  version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: ffi
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
96
  - !ruby/object:Gem::Dependency
112
97
  name: leb128
113
98
  requirement: !ruby/object:Gem::Requirement
@@ -164,20 +149,6 @@ dependencies:
164
149
  - - ">="
165
150
  - !ruby/object:Gem::Version
166
151
  version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: json_pure
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: 2.3.1
174
- type: :runtime
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: 2.3.1
181
152
  - !ruby/object:Gem::Dependency
182
153
  name: bip-schnorr
183
154
  requirement: !ruby/object:Gem::Requirement
@@ -207,103 +178,61 @@ dependencies:
207
178
  - !ruby/object:Gem::Version
208
179
  version: 0.3.4
209
180
  - !ruby/object:Gem::Dependency
210
- name: leveldb-native
211
- requirement: !ruby/object:Gem::Requirement
212
- requirements:
213
- - - ">="
214
- - !ruby/object:Gem::Version
215
- version: '0'
216
- type: :development
217
- prerelease: false
218
- version_requirements: !ruby/object:Gem::Requirement
219
- requirements:
220
- - - ">="
221
- - !ruby/object:Gem::Version
222
- version: '0'
223
- - !ruby/object:Gem::Dependency
224
- name: bundler
225
- requirement: !ruby/object:Gem::Requirement
226
- requirements:
227
- - - ">="
228
- - !ruby/object:Gem::Version
229
- version: '0'
230
- type: :development
231
- prerelease: false
232
- version_requirements: !ruby/object:Gem::Requirement
233
- requirements:
234
- - - ">="
235
- - !ruby/object:Gem::Version
236
- version: '0'
237
- - !ruby/object:Gem::Dependency
238
- name: rake
239
- requirement: !ruby/object:Gem::Requirement
240
- requirements:
241
- - - ">="
242
- - !ruby/object:Gem::Version
243
- version: 12.3.3
244
- type: :development
245
- prerelease: false
246
- version_requirements: !ruby/object:Gem::Requirement
247
- requirements:
248
- - - ">="
249
- - !ruby/object:Gem::Version
250
- version: 12.3.3
251
- - !ruby/object:Gem::Dependency
252
- name: rspec
181
+ name: base64
253
182
  requirement: !ruby/object:Gem::Requirement
254
183
  requirements:
255
184
  - - "~>"
256
185
  - !ruby/object:Gem::Version
257
- version: '3.0'
258
- type: :development
186
+ version: 0.2.0
187
+ type: :runtime
259
188
  prerelease: false
260
189
  version_requirements: !ruby/object:Gem::Requirement
261
190
  requirements:
262
191
  - - "~>"
263
192
  - !ruby/object:Gem::Version
264
- version: '3.0'
193
+ version: 0.2.0
265
194
  - !ruby/object:Gem::Dependency
266
- name: timecop
195
+ name: observer
267
196
  requirement: !ruby/object:Gem::Requirement
268
197
  requirements:
269
- - - ">="
198
+ - - "~>"
270
199
  - !ruby/object:Gem::Version
271
- version: '0'
272
- type: :development
200
+ version: 0.1.2
201
+ type: :runtime
273
202
  prerelease: false
274
203
  version_requirements: !ruby/object:Gem::Requirement
275
204
  requirements:
276
- - - ">="
205
+ - - "~>"
277
206
  - !ruby/object:Gem::Version
278
- version: '0'
207
+ version: 0.1.2
279
208
  - !ruby/object:Gem::Dependency
280
- name: webmock
209
+ name: secp256k1rb
281
210
  requirement: !ruby/object:Gem::Requirement
282
211
  requirements:
283
- - - ">="
212
+ - - '='
284
213
  - !ruby/object:Gem::Version
285
- version: 3.11.1
286
- type: :development
214
+ version: 0.1.1
215
+ type: :runtime
287
216
  prerelease: false
288
217
  version_requirements: !ruby/object:Gem::Requirement
289
218
  requirements:
290
- - - ">="
219
+ - - '='
291
220
  - !ruby/object:Gem::Version
292
- version: 3.11.1
221
+ version: 0.1.1
293
222
  - !ruby/object:Gem::Dependency
294
- name: parallel
223
+ name: logger
295
224
  requirement: !ruby/object:Gem::Requirement
296
225
  requirements:
297
226
  - - ">="
298
227
  - !ruby/object:Gem::Version
299
- version: 1.20.1
300
- type: :development
228
+ version: '0'
229
+ type: :runtime
301
230
  prerelease: false
302
231
  version_requirements: !ruby/object:Gem::Requirement
303
232
  requirements:
304
233
  - - ">="
305
234
  - !ruby/object:Gem::Version
306
- version: 1.20.1
235
+ version: '0'
307
236
  description: The implementation of Bitcoin Protocol for Ruby.
308
237
  email:
309
238
  - azuchi@chaintope.com
@@ -348,6 +277,7 @@ files:
348
277
  - lib/bitcoin/chainparams/regtest.yml
349
278
  - lib/bitcoin/chainparams/signet.yml
350
279
  - lib/bitcoin/chainparams/testnet.yml
280
+ - lib/bitcoin/chainparams/testnet4.yml
351
281
  - lib/bitcoin/constants.rb
352
282
  - lib/bitcoin/descriptor.rb
353
283
  - lib/bitcoin/descriptor/addr.rb
@@ -372,7 +302,6 @@ files:
372
302
  - lib/bitcoin/ext.rb
373
303
  - lib/bitcoin/ext/array_ext.rb
374
304
  - lib/bitcoin/ext/ecdsa.rb
375
- - lib/bitcoin/ext/json_parser.rb
376
305
  - lib/bitcoin/ext/object_ext.rb
377
306
  - lib/bitcoin/ext_key.rb
378
307
  - lib/bitcoin/gcs_filter.rb
@@ -507,7 +436,6 @@ homepage: https://github.com/chaintope/bitcoinrb
507
436
  licenses:
508
437
  - MIT
509
438
  metadata: {}
510
- post_install_message:
511
439
  rdoc_options: []
512
440
  require_paths:
513
441
  - lib
@@ -522,8 +450,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
522
450
  - !ruby/object:Gem::Version
523
451
  version: '0'
524
452
  requirements: []
525
- rubygems_version: 3.5.3
526
- signing_key:
453
+ rubygems_version: 3.6.3
527
454
  specification_version: 4
528
455
  summary: The implementation of Bitcoin Protocol for Ruby.
529
456
  test_files: []
@@ -1,46 +0,0 @@
1
- require 'json/pure'
2
-
3
- module Bitcoin
4
- module Ext
5
- # Extension of JSON::Pure::Parser.
6
- # This class convert Float value to String value.
7
- class JsonParser < JSON::Pure::Parser
8
-
9
- def parse_value
10
- case
11
- when scan(FLOAT)
12
- self[1].to_s
13
- when scan(INTEGER)
14
- Integer(self[1])
15
- when scan(TRUE)
16
- true
17
- when scan(FALSE)
18
- false
19
- when scan(NULL)
20
- nil
21
- when !UNPARSED.equal?(string = parse_string)
22
- string
23
- when scan(ARRAY_OPEN)
24
- @current_nesting += 1
25
- ary = parse_array
26
- @current_nesting -= 1
27
- ary
28
- when scan(OBJECT_OPEN)
29
- @current_nesting += 1
30
- obj = parse_object
31
- @current_nesting -= 1
32
- obj
33
- when @allow_nan && scan(NAN)
34
- NaN
35
- when @allow_nan && scan(INFINITY)
36
- Infinity
37
- when @allow_nan && scan(MINUS_INFINITY)
38
- MinusInfinity
39
- else
40
- UNPARSED
41
- end
42
- end
43
-
44
- end
45
- end
46
- end