bitcoinrb 1.7.0 → 1.8.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.ruby-version +1 -1
- data/Gemfile +8 -0
- data/bitcoinrb.gemspec +4 -12
- data/lib/bitcoin/bip324/ell_swift_pubkey.rb +1 -1
- data/lib/bitcoin/bip324.rb +2 -2
- data/lib/bitcoin/chain_params.rb +9 -0
- data/lib/bitcoin/chainparams/mainnet.yml +6 -2
- data/lib/bitcoin/chainparams/regtest.yml +1 -2
- data/lib/bitcoin/chainparams/signet.yml +3 -4
- data/lib/bitcoin/chainparams/testnet.yml +4 -4
- data/lib/bitcoin/chainparams/testnet4.yml +38 -0
- data/lib/bitcoin/key.rb +2 -5
- data/lib/bitcoin/message_sign.rb +23 -4
- data/lib/bitcoin/psbt.rb +0 -2
- data/lib/bitcoin/secp256k1/native.rb +53 -347
- data/lib/bitcoin/secp256k1/ruby.rb +19 -3
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin.rb +1 -1
- metadata +26 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0cc5450016d6ffbb76d36dcccd415a485a8532ab8414d9beddb9a7e25305dba
|
4
|
+
data.tar.gz: 75d509c36069ce2dee667a0330962ae310c8062f24aa01d299e5692f6f069461
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2457464548bd24c937eaf55aa53ff2b7ca01b5db0b57b66d7e6fef60142cde6ff2752d670e06bd6052470b6eef25af9f3b676ffe1842fd98c1fd9d590888556
|
7
|
+
data.tar.gz: 95d5649e3cacc1a155b0e033f0275d9f1806a9e39aad2bbe0c9b61809a10b76d117dddf94c0c68eae50e9dd52aa8e3f266244e2a400821d9172e2706a371c654
|
data/.github/workflows/ruby.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-3.
|
1
|
+
ruby-3.4.1
|
data/Gemfile
CHANGED
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'
|
33
|
+
spec.add_runtime_dependency 'json_pure', '>= 2.3.1', '< 2.8.0'
|
35
34
|
spec.add_runtime_dependency 'bip-schnorr', '>= 0.7.0'
|
36
35
|
spec.add_runtime_dependency 'base32', '>= 0.3.4'
|
37
|
-
|
38
|
-
|
39
|
-
spec.
|
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'
|
36
|
+
spec.add_runtime_dependency 'base64', '~> 0.2.0'
|
37
|
+
spec.add_runtime_dependency 'observer', '~> 0.1.2'
|
38
|
+
spec.add_runtime_dependency 'secp256k1rb', '0.1.1'
|
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.
|
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
|
data/lib/bitcoin/bip324.rb
CHANGED
@@ -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.
|
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 :
|
data/lib/bitcoin/chain_params.rb
CHANGED
@@ -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.
|
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:
|
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:
|
26
|
-
genesis_hash: "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
|
25
|
+
bip34_height: 1
|
27
26
|
proof_of_work_limit: 0x1d00ffff
|
28
27
|
dns_seeds:
|
29
|
-
- "
|
30
|
-
- "
|
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:
|
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.
|
29
|
+
- "seed.tbtc.petertodd.net"
|
30
|
+
- "seed.testnet.bitcoin.sprovoost.nl"
|
31
31
|
- "testnet-seed.bluematt.me"
|
32
|
-
- "
|
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/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,
|
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.
|
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))
|
data/lib/bitcoin/message_sign.rb
CHANGED
@@ -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
|
66
|
-
|
65
|
+
rescue Exception
|
66
|
+
false
|
67
67
|
end
|
68
68
|
elsif addr_script.witness_program?
|
69
69
|
# BIP322 verification
|
70
|
-
|
71
|
-
|
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,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
|
-
|
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
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
135
|
-
|
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,
|
159
|
-
|
160
|
-
|
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
|
-
#
|
176
|
-
# @param [String] data
|
177
|
-
# @param [String]
|
178
|
-
# @param [String]
|
179
|
-
#
|
180
|
-
# @return [
|
181
|
-
|
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
|
-
|
60
|
+
begin
|
61
|
+
sign_ecdsa(data, private_key, extra_entropy)
|
62
|
+
rescue ArgumentError
|
63
|
+
false
|
64
|
+
end
|
185
65
|
when :schnorr
|
186
|
-
|
66
|
+
begin
|
67
|
+
sign_schnorr(data, private_key, extra_entropy)
|
68
|
+
rescue ArgumentError
|
69
|
+
false
|
70
|
+
end
|
187
71
|
else
|
188
|
-
|
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
|
-
#
|
208
|
-
# @param [String]
|
209
|
-
# @
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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
|
-
|
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])
|
data/lib/bitcoin/version.rb
CHANGED
data/lib/bitcoin.rb
CHANGED
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.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-03 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
|
@@ -171,6 +156,9 @@ dependencies:
|
|
171
156
|
- - ">="
|
172
157
|
- !ruby/object:Gem::Version
|
173
158
|
version: 2.3.1
|
159
|
+
- - "<"
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: 2.8.0
|
174
162
|
type: :runtime
|
175
163
|
prerelease: false
|
176
164
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -178,6 +166,9 @@ dependencies:
|
|
178
166
|
- - ">="
|
179
167
|
- !ruby/object:Gem::Version
|
180
168
|
version: 2.3.1
|
169
|
+
- - "<"
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: 2.8.0
|
181
172
|
- !ruby/object:Gem::Dependency
|
182
173
|
name: bip-schnorr
|
183
174
|
requirement: !ruby/object:Gem::Requirement
|
@@ -207,103 +198,47 @@ dependencies:
|
|
207
198
|
- !ruby/object:Gem::Version
|
208
199
|
version: 0.3.4
|
209
200
|
- !ruby/object:Gem::Dependency
|
210
|
-
name:
|
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
|
201
|
+
name: base64
|
253
202
|
requirement: !ruby/object:Gem::Requirement
|
254
203
|
requirements:
|
255
204
|
- - "~>"
|
256
205
|
- !ruby/object:Gem::Version
|
257
|
-
version:
|
258
|
-
type: :
|
206
|
+
version: 0.2.0
|
207
|
+
type: :runtime
|
259
208
|
prerelease: false
|
260
209
|
version_requirements: !ruby/object:Gem::Requirement
|
261
210
|
requirements:
|
262
211
|
- - "~>"
|
263
212
|
- !ruby/object:Gem::Version
|
264
|
-
version:
|
213
|
+
version: 0.2.0
|
265
214
|
- !ruby/object:Gem::Dependency
|
266
|
-
name:
|
215
|
+
name: observer
|
267
216
|
requirement: !ruby/object:Gem::Requirement
|
268
217
|
requirements:
|
269
|
-
- - "
|
270
|
-
- !ruby/object:Gem::Version
|
271
|
-
version: '0'
|
272
|
-
type: :development
|
273
|
-
prerelease: false
|
274
|
-
version_requirements: !ruby/object:Gem::Requirement
|
275
|
-
requirements:
|
276
|
-
- - ">="
|
277
|
-
- !ruby/object:Gem::Version
|
278
|
-
version: '0'
|
279
|
-
- !ruby/object:Gem::Dependency
|
280
|
-
name: webmock
|
281
|
-
requirement: !ruby/object:Gem::Requirement
|
282
|
-
requirements:
|
283
|
-
- - ">="
|
218
|
+
- - "~>"
|
284
219
|
- !ruby/object:Gem::Version
|
285
|
-
version:
|
286
|
-
type: :
|
220
|
+
version: 0.1.2
|
221
|
+
type: :runtime
|
287
222
|
prerelease: false
|
288
223
|
version_requirements: !ruby/object:Gem::Requirement
|
289
224
|
requirements:
|
290
|
-
- - "
|
225
|
+
- - "~>"
|
291
226
|
- !ruby/object:Gem::Version
|
292
|
-
version:
|
227
|
+
version: 0.1.2
|
293
228
|
- !ruby/object:Gem::Dependency
|
294
|
-
name:
|
229
|
+
name: secp256k1rb
|
295
230
|
requirement: !ruby/object:Gem::Requirement
|
296
231
|
requirements:
|
297
|
-
- -
|
232
|
+
- - '='
|
298
233
|
- !ruby/object:Gem::Version
|
299
|
-
version: 1.
|
300
|
-
type: :
|
234
|
+
version: 0.1.1
|
235
|
+
type: :runtime
|
301
236
|
prerelease: false
|
302
237
|
version_requirements: !ruby/object:Gem::Requirement
|
303
238
|
requirements:
|
304
|
-
- -
|
239
|
+
- - '='
|
305
240
|
- !ruby/object:Gem::Version
|
306
|
-
version: 1.
|
241
|
+
version: 0.1.1
|
307
242
|
description: The implementation of Bitcoin Protocol for Ruby.
|
308
243
|
email:
|
309
244
|
- azuchi@chaintope.com
|
@@ -348,6 +283,7 @@ files:
|
|
348
283
|
- lib/bitcoin/chainparams/regtest.yml
|
349
284
|
- lib/bitcoin/chainparams/signet.yml
|
350
285
|
- lib/bitcoin/chainparams/testnet.yml
|
286
|
+
- lib/bitcoin/chainparams/testnet4.yml
|
351
287
|
- lib/bitcoin/constants.rb
|
352
288
|
- lib/bitcoin/descriptor.rb
|
353
289
|
- lib/bitcoin/descriptor/addr.rb
|
@@ -507,7 +443,6 @@ homepage: https://github.com/chaintope/bitcoinrb
|
|
507
443
|
licenses:
|
508
444
|
- MIT
|
509
445
|
metadata: {}
|
510
|
-
post_install_message:
|
511
446
|
rdoc_options: []
|
512
447
|
require_paths:
|
513
448
|
- lib
|
@@ -522,8 +457,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
522
457
|
- !ruby/object:Gem::Version
|
523
458
|
version: '0'
|
524
459
|
requirements: []
|
525
|
-
rubygems_version: 3.
|
526
|
-
signing_key:
|
460
|
+
rubygems_version: 3.6.2
|
527
461
|
specification_version: 4
|
528
462
|
summary: The implementation of Bitcoin Protocol for Ruby.
|
529
463
|
test_files: []
|