bitcoinrb 0.5.0 → 0.9.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 +37 -0
- data/.rspec_parallel +2 -0
- data/.ruby-version +1 -1
- data/README.md +11 -1
- data/bitcoinrb.gemspec +7 -6
- data/lib/bitcoin/block_filter.rb +14 -0
- data/lib/bitcoin/chain_params.rb +9 -0
- data/lib/bitcoin/chainparams/signet.yml +39 -0
- data/lib/bitcoin/constants.rb +45 -4
- data/lib/bitcoin/descriptor.rb +1 -1
- data/lib/bitcoin/errors.rb +19 -0
- data/lib/bitcoin/ext/array_ext.rb +22 -0
- data/lib/bitcoin/ext/ecdsa.rb +36 -0
- data/lib/bitcoin/ext.rb +1 -0
- data/lib/bitcoin/ext_key.rb +36 -20
- data/lib/bitcoin/key.rb +85 -28
- data/lib/bitcoin/message/addr_v2.rb +34 -0
- data/lib/bitcoin/message/base.rb +16 -0
- data/lib/bitcoin/message/cfcheckpt.rb +2 -2
- data/lib/bitcoin/message/cfheaders.rb +1 -1
- data/lib/bitcoin/message/cfilter.rb +1 -1
- data/lib/bitcoin/message/fee_filter.rb +1 -1
- data/lib/bitcoin/message/filter_load.rb +3 -3
- data/lib/bitcoin/message/header_and_short_ids.rb +1 -1
- data/lib/bitcoin/message/inventory.rb +1 -1
- data/lib/bitcoin/message/merkle_block.rb +1 -1
- data/lib/bitcoin/message/network_addr.rb +141 -18
- data/lib/bitcoin/message/ping.rb +1 -1
- data/lib/bitcoin/message/pong.rb +1 -1
- data/lib/bitcoin/message/send_addr_v2.rb +13 -0
- data/lib/bitcoin/message/send_cmpct.rb +2 -2
- data/lib/bitcoin/message/tx.rb +1 -1
- data/lib/bitcoin/message.rb +72 -0
- data/lib/bitcoin/message_sign.rb +47 -0
- data/lib/bitcoin/mnemonic.rb +2 -2
- data/lib/bitcoin/network/peer_discovery.rb +1 -3
- data/lib/bitcoin/node/configuration.rb +3 -1
- data/lib/bitcoin/node/spv.rb +8 -0
- data/lib/bitcoin/opcodes.rb +14 -1
- data/lib/bitcoin/payment_code.rb +2 -2
- data/lib/bitcoin/payments/payment.pb.rb +1 -1
- data/lib/bitcoin/psbt/hd_key_path.rb +1 -1
- data/lib/bitcoin/psbt/input.rb +4 -4
- data/lib/bitcoin/psbt/output.rb +1 -1
- data/lib/bitcoin/psbt/tx.rb +14 -5
- data/lib/bitcoin/psbt.rb +8 -0
- data/lib/bitcoin/rpc/bitcoin_core_client.rb +1 -1
- data/lib/bitcoin/rpc/request_handler.rb +3 -3
- data/lib/bitcoin/script/script.rb +80 -30
- data/lib/bitcoin/script/script_error.rb +27 -1
- data/lib/bitcoin/script/script_interpreter.rb +164 -62
- data/lib/bitcoin/script/tx_checker.rb +62 -14
- data/lib/bitcoin/secp256k1/native.rb +184 -17
- data/lib/bitcoin/secp256k1/ruby.rb +108 -21
- data/lib/bitcoin/sighash_generator.rb +157 -0
- data/lib/bitcoin/taproot/leaf_node.rb +23 -0
- data/lib/bitcoin/taproot/simple_builder.rb +155 -0
- data/lib/bitcoin/taproot.rb +45 -0
- data/lib/bitcoin/tx.rb +30 -96
- data/lib/bitcoin/tx_in.rb +1 -1
- data/lib/bitcoin/tx_out.rb +2 -3
- data/lib/bitcoin/util.rb +15 -6
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/account.rb +1 -1
- data/lib/bitcoin.rb +32 -24
- metadata +58 -18
- data/.travis.yml +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8103017ba6b480dc45caea8b9544720003c486167c3e867be738ccdc40faef7
|
4
|
+
data.tar.gz: 3807ee81a2ed26a526c19903c616ebb7af5b2a9c8434a76398e538a02c34e126
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97a9df2fee4c9d2fb7c84555d82e0f1ef692e0889c964fc7615f328467925a5b099be19801b19321a9b12fc55493663f1813be4074e5fc95add8948cd52ca2e4
|
7
|
+
data.tar.gz: '0370268e40a85bf6face9592b8dc3cf260b6357e796f62c7e6abddaeeef2d3ec561e4336ba859c5f8426dcedd80eba6d9ec632941e284791df9571ff613182e5'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
strategy:
|
21
|
+
matrix:
|
22
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
23
|
+
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Install leveldb
|
27
|
+
run: sudo apt-get install libleveldb-dev
|
28
|
+
- name: Set up Ruby
|
29
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
30
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
31
|
+
# uses: ruby/setup-ruby@v1
|
32
|
+
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
33
|
+
with:
|
34
|
+
ruby-version: ${{ matrix.ruby-version }}
|
35
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
36
|
+
- name: Run tests
|
37
|
+
run: bundle exec rake spec
|
data/.rspec_parallel
ADDED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
ruby-3.0.2
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Bitcoinrb [](https://github.com/chaintope/bitcoinrb/actions/workflows/ruby.yml) [](https://badge.fury.io/rb/bitcoinrb) [](LICENSE) <img src="http://segwit.co/static/public/images/logo.png" width="100">
|
2
2
|
|
3
3
|
|
4
4
|
Bitcoinrb is a Ruby implementation of Bitcoin Protocol.
|
@@ -18,6 +18,8 @@ Bitcoinrb supports following feature:
|
|
18
18
|
* [BIP-173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) Bech32 address support
|
19
19
|
* [BIP-174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) PSBT(Partially Signed Bitcoin Transaction) support
|
20
20
|
* [BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki) Deterministic Entropy From BIP32 Keychains support by `Bitcoin::BIP85Entropy` class.
|
21
|
+
* Schnorr signature([BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki))
|
22
|
+
* Taproot consensus([BIP-341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) and [BIP-342](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki))
|
21
23
|
* [WIP] SPV node
|
22
24
|
* [WIP] 0ff-chain protocol
|
23
25
|
|
@@ -93,6 +95,14 @@ Bitcoin.chain_params = :regtest
|
|
93
95
|
|
94
96
|
This parameter is described in https://github.com/chaintope/bitcoinrb/blob/master/lib/bitcoin/chainparams/regtest.yml.
|
95
97
|
|
98
|
+
* default signet
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Bitcoin.chain_params = :signet
|
102
|
+
```
|
103
|
+
|
104
|
+
This parameter is described in https://github.com/chaintope/bitcoinrb/blob/master/lib/bitcoin/chainparams/signet.yml.
|
105
|
+
|
96
106
|
## Contributing
|
97
107
|
|
98
108
|
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/bitcoinrb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/bitcoinrb.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ["azuchi"]
|
11
11
|
spec.email = ["azuchi@chaintope.com"]
|
12
12
|
|
13
|
-
spec.summary = %q{
|
14
|
-
spec.description = %q{
|
13
|
+
spec.summary = %q{The implementation of Bitcoin Protocol for Ruby.}
|
14
|
+
spec.description = %q{The implementation of Bitcoin Protocol for Ruby.}
|
15
15
|
spec.homepage = 'https://github.com/chaintope/bitcoinrb'
|
16
16
|
spec.license = "MIT"
|
17
17
|
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_runtime_dependency 'ecdsa'
|
24
24
|
spec.add_runtime_dependency 'eventmachine'
|
25
25
|
spec.add_runtime_dependency 'murmurhash3'
|
26
|
-
spec.add_runtime_dependency 'bech32', '~> 1.0
|
26
|
+
spec.add_runtime_dependency 'bech32', '~> 1.1.0'
|
27
27
|
spec.add_runtime_dependency 'daemon-spawn'
|
28
28
|
spec.add_runtime_dependency 'thor'
|
29
29
|
spec.add_runtime_dependency 'ffi'
|
@@ -32,8 +32,9 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_runtime_dependency 'iniparse'
|
33
33
|
spec.add_runtime_dependency 'siphash'
|
34
34
|
spec.add_runtime_dependency 'protobuf', '3.8.5'
|
35
|
-
spec.add_runtime_dependency 'scrypt'
|
36
35
|
spec.add_runtime_dependency 'json_pure', '>= 2.3.1'
|
36
|
+
spec.add_runtime_dependency 'bip-schnorr', '>= 0.4.0'
|
37
|
+
spec.add_runtime_dependency 'base32', '>= 0.3.4'
|
37
38
|
|
38
39
|
# for options
|
39
40
|
spec.add_development_dependency 'leveldb-native'
|
@@ -42,6 +43,6 @@ Gem::Specification.new do |spec|
|
|
42
43
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
43
44
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
44
45
|
spec.add_development_dependency 'timecop'
|
45
|
-
spec.add_development_dependency 'webmock', '
|
46
|
-
|
46
|
+
spec.add_development_dependency 'webmock', '>= 3.11.1'
|
47
|
+
spec.add_development_dependency 'parallel', '>= 1.20.1'
|
47
48
|
end
|
data/lib/bitcoin/block_filter.rb
CHANGED
@@ -43,6 +43,20 @@ module Bitcoin
|
|
43
43
|
BlockFilter.new(filter_type, filter, block.block_hash)
|
44
44
|
end
|
45
45
|
|
46
|
+
# Decode Block Filter from encoded filter
|
47
|
+
# @param [Integer] filter_type filter type.
|
48
|
+
# @param [String] block_hash block hash with hex format. not little endian.
|
49
|
+
# @param [String] encoded encoded_filter with hex format.
|
50
|
+
# @return [Bitcoin::BlockFilter] block filter object.
|
51
|
+
def self.decode(filter_type, block_hash, encoded)
|
52
|
+
filter = case filter_type
|
53
|
+
when TYPE[:basic]
|
54
|
+
GCSFilter.new(block_hash.htb[0...16], BASIC_FILTER_P, BASIC_FILTER_M, encoded_filter: encoded)
|
55
|
+
else
|
56
|
+
raise "unknown filter type: #{filter_type}."
|
57
|
+
end
|
58
|
+
BlockFilter.new(filter_type, filter, block_hash)
|
59
|
+
end
|
46
60
|
|
47
61
|
# calculate filter hash.
|
48
62
|
# @return [String] this filter hash with hex format.
|
data/lib/bitcoin/chain_params.rb
CHANGED
@@ -51,6 +51,11 @@ module Bitcoin
|
|
51
51
|
init('regtest')
|
52
52
|
end
|
53
53
|
|
54
|
+
# signet genesis
|
55
|
+
def self.signet
|
56
|
+
init('signet')
|
57
|
+
end
|
58
|
+
|
54
59
|
def mainnet?
|
55
60
|
network == 'mainnet'
|
56
61
|
end
|
@@ -63,6 +68,10 @@ module Bitcoin
|
|
63
68
|
network == 'regtest'
|
64
69
|
end
|
65
70
|
|
71
|
+
def signet?
|
72
|
+
network == 'signet'
|
73
|
+
end
|
74
|
+
|
66
75
|
def genesis_block
|
67
76
|
header = Bitcoin::BlockHeader.new(
|
68
77
|
genesis['version'], genesis['prev_hash'].rhex, genesis['merkle_root'].rhex,
|
@@ -0,0 +1,39 @@
|
|
1
|
+
--- !ruby/object:Bitcoin::ChainParams
|
2
|
+
network: "signet"
|
3
|
+
magic_head: "0a03cf40"
|
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: 38333
|
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: 227931
|
26
|
+
genesis_hash: "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
|
27
|
+
proof_of_work_limit: 0x1d00ffff
|
28
|
+
dns_seeds:
|
29
|
+
- "178.128.221.177"
|
30
|
+
- "2a01:7c8:d005:390::5"
|
31
|
+
genesis:
|
32
|
+
hash: "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
|
33
|
+
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
34
|
+
time: 1598918400
|
35
|
+
nonce: 52613770
|
36
|
+
bits: 0x1e0377ae
|
37
|
+
version: 1
|
38
|
+
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
39
|
+
bip44_coin_type: 1
|
data/lib/bitcoin/constants.rb
CHANGED
@@ -44,6 +44,11 @@ module Bitcoin
|
|
44
44
|
SCRIPT_VERIFY_NULLFAIL = (1 << 14) # Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
|
45
45
|
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1 << 15) # Public keys in segregated witness scripts must be compressed
|
46
46
|
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1 << 16) # Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
47
|
+
SCRIPT_VERIFY_TAPROOT = (1 << 17) # Taproot/Tapscript validation (BIPs 341 & 342)
|
48
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1 << 18) # Making unknown Taproot leaf versions non-standard
|
49
|
+
SCRIPT_VERIFY_DISCOURAGE_UNKNOWN_ANNEX = (1 << 19) # Making the use of (unknown) annexes non-standard (currently no annexes are known)
|
50
|
+
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1 << 20) # Making unknown OP_SUCCESS non-standard
|
51
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1 << 21) # Making unknown public key versions (in BIP 342 scripts) non-standard
|
47
52
|
|
48
53
|
MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH
|
49
54
|
|
@@ -68,7 +73,8 @@ module Bitcoin
|
|
68
73
|
# for script
|
69
74
|
|
70
75
|
# witness version
|
71
|
-
|
76
|
+
WITNESS_VERSION_V0 = 0x00
|
77
|
+
WITNESS_VERSION_V1 = Bitcoin::Opcodes::OP_1
|
72
78
|
|
73
79
|
# Maximum script length in bytes
|
74
80
|
MAX_SCRIPT_SIZE = 10000
|
@@ -88,8 +94,19 @@ module Bitcoin
|
|
88
94
|
# Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
|
89
95
|
LOCKTIME_THRESHOLD = 500000000
|
90
96
|
|
97
|
+
# Tag for input annex. If there are at least two witness elements for a transaction input,
|
98
|
+
# and the first byte of the last element is 0x50, this last element is called annex, and
|
99
|
+
# has meanings independent of the script
|
100
|
+
ANNEX_TAG = 0x50
|
101
|
+
|
102
|
+
# Validation weight per passing signature (Tapscript only, see BIP 342).
|
103
|
+
VALIDATION_WEIGHT_PER_SIGOP_PASSED = 50
|
104
|
+
|
105
|
+
# How much weight budget is added to the witness size (Tapscript only, see BIP 342).
|
106
|
+
VALIDATION_WEIGHT_OFFSET = 50
|
107
|
+
|
91
108
|
# Signature hash types/flags
|
92
|
-
SIGHASH_TYPE = { all:
|
109
|
+
SIGHASH_TYPE = { all: 0x01, none: 0x02, single: 0x3, anyonecanpay: 0x80 , default: 0}
|
93
110
|
|
94
111
|
# Maximum number length in bytes
|
95
112
|
DEFAULT_MAX_NUM_SIZE = 4
|
@@ -97,8 +114,6 @@ module Bitcoin
|
|
97
114
|
# 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes.
|
98
115
|
MAX_OP_RETURN_RELAY = 83
|
99
116
|
|
100
|
-
SIG_VERSION = [:base, :witness_v0]
|
101
|
-
|
102
117
|
# for script error
|
103
118
|
SCRIPT_ERR_OK = 0
|
104
119
|
SCRIPT_ERR_UNKNOWN_ERROR = 1
|
@@ -146,6 +161,10 @@ module Bitcoin
|
|
146
161
|
# softfork safeness
|
147
162
|
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS = 60
|
148
163
|
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = 61
|
164
|
+
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = 62
|
165
|
+
SCRIPT_ERR_DISCOURAGE_UNKNOWN_ANNEX = 63
|
166
|
+
SCRIPT_ERR_DISCOURAGE_OP_SUCCESS = 64
|
167
|
+
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = 65
|
149
168
|
|
150
169
|
# segregated witness
|
151
170
|
SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH = 70
|
@@ -162,6 +181,15 @@ module Bitcoin
|
|
162
181
|
|
163
182
|
SCRIPT_ERR_ERROR_COUNT = 80
|
164
183
|
|
184
|
+
# Taproot
|
185
|
+
SCRIPT_ERR_SCHNORR_SIG_SIZE = 90
|
186
|
+
SCRIPT_ERR_SCHNORR_SIG_HASHTYPE = 91
|
187
|
+
SCRIPT_ERR_SCHNORR_SIG = 92
|
188
|
+
SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE = 93
|
189
|
+
SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT = 94
|
190
|
+
SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG = 95
|
191
|
+
SCRIPT_ERR_TAPSCRIPT_MINIMALIF = 96
|
192
|
+
|
165
193
|
ERRCODES_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [const_get(c), c.to_s] }.flatten]
|
166
194
|
NAME_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
167
195
|
|
@@ -185,4 +213,17 @@ module Bitcoin
|
|
185
213
|
BIP32_EXTKEY_WITH_VERSION_SIZE = 78
|
186
214
|
|
187
215
|
HARDENED_THRESHOLD = 2147483648 # 2**31
|
216
|
+
|
217
|
+
# Signature hash sizes
|
218
|
+
WITNESS_V0_SCRIPTHASH_SIZE = 32
|
219
|
+
WITNESS_V0_KEYHASH_SIZE = 20
|
220
|
+
WITNESS_V1_TAPROOT_SIZE = 32
|
221
|
+
|
222
|
+
TAPROOT_LEAF_MASK = 0xfe
|
223
|
+
TAPROOT_LEAF_TAPSCRIPT = 0xc0
|
224
|
+
TAPROOT_CONTROL_BASE_SIZE = 33
|
225
|
+
TAPROOT_CONTROL_NODE_SIZE = 32
|
226
|
+
TAPROOT_CONTROL_MAX_NODE_COUNT = 128
|
227
|
+
TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT
|
228
|
+
|
188
229
|
end
|
data/lib/bitcoin/descriptor.rb
CHANGED
@@ -116,7 +116,7 @@ module Bitcoin
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
key = key.is_a?(Bitcoin::Key) ? key : key.key
|
119
|
-
raise ArgumentError,
|
119
|
+
raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless key.fully_valid_pubkey?
|
120
120
|
key.pubkey
|
121
121
|
end
|
122
122
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Errors
|
3
|
+
|
4
|
+
module Messages
|
5
|
+
|
6
|
+
INVALID_PUBLIC_KEY = 'Invalid public key.'
|
7
|
+
INVALID_BIP32_PRIV_PREFIX = 'Invalid BIP32 private key prefix. prefix must be 0x00.'
|
8
|
+
INVALID_BIP32_FINGERPRINT = 'Invalid parent fingerprint.'
|
9
|
+
INVALID_BIP32_ZERO_INDEX = 'Invalid index. Depth 0 must have 0 index.'
|
10
|
+
INVALID_BIP32_ZERO_DEPTH = 'Invalid depth. Master key must have 0 depth.'
|
11
|
+
INVALID_BIP32_VERSION = 'An unsupported version byte was specified.'
|
12
|
+
|
13
|
+
INVALID_PRIV_KEY = 'Private key is not in range [1..n-1].'
|
14
|
+
INVALID_CHECKSUM = 'Invalid checksum.'
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Ext
|
3
|
+
module ArrayExt
|
4
|
+
|
5
|
+
refine Array do
|
6
|
+
|
7
|
+
# resize array content with +initial_value+.
|
8
|
+
# expect to behave like vec#resize in c++.
|
9
|
+
def resize!(new_size, initial_value = 0)
|
10
|
+
if size < new_size
|
11
|
+
(new_size - size).times{self.<< initial_value}
|
12
|
+
elsif size > new_size
|
13
|
+
(size - new_size).times{delete_at(-1)}
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ::ECDSA::Signature
|
2
|
+
# convert signature to der string.
|
3
|
+
def to_der
|
4
|
+
ECDSA::Format::SignatureDerString.encode(self)
|
5
|
+
end
|
6
|
+
|
7
|
+
def ==(other)
|
8
|
+
return false unless other.is_a?(ECDSA::Signature)
|
9
|
+
r == other.r && s == other.s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ::ECDSA::Point
|
14
|
+
def to_hex(compression = true)
|
15
|
+
ECDSA::Format::PointOctetString.encode(self, compression: compression).bth
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ::ECDSA::Format::PointOctetString
|
20
|
+
|
21
|
+
class << self
|
22
|
+
alias_method :base_decode, :decode
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.decode(string, group, allow_hybrid: false)
|
26
|
+
string = string.dup.force_encoding('BINARY')
|
27
|
+
raise ECDSA::Format::DecodeError, 'Point octet string is empty.' if string.empty?
|
28
|
+
if [6, 7].include?(string[0].ord)
|
29
|
+
raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord unless allow_hybrid
|
30
|
+
decode_uncompressed string, group if allow_hybrid
|
31
|
+
else
|
32
|
+
base_decode(string, group)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/bitcoin/ext.rb
CHANGED
data/lib/bitcoin/ext_key.rb
CHANGED
@@ -52,9 +52,7 @@ module Bitcoin
|
|
52
52
|
|
53
53
|
# Base58 encoded extended private key
|
54
54
|
def to_base58
|
55
|
-
|
56
|
-
hex = h + Bitcoin.calc_checksum(h)
|
57
|
-
Base58.encode(hex)
|
55
|
+
ExtPubkey.encode_base58(to_hex)
|
58
56
|
end
|
59
57
|
|
60
58
|
# get private key(hex)
|
@@ -146,22 +144,24 @@ module Bitcoin
|
|
146
144
|
buf = StringIO.new(payload)
|
147
145
|
ext_key = ExtKey.new
|
148
146
|
ext_key.ver = buf.read(4).bth # version
|
149
|
-
raise
|
150
|
-
ext_key.depth = buf.read(1).
|
147
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_VERSION unless ExtKey.support_version?(ext_key.ver)
|
148
|
+
ext_key.depth = buf.read(1).unpack1('C')
|
151
149
|
ext_key.parent_fingerprint = buf.read(4).bth
|
150
|
+
ext_key.number = buf.read(4).unpack1('N')
|
152
151
|
if ext_key.depth == 0
|
153
|
-
raise ArgumentError,
|
152
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT unless ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
153
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_key.number > 0
|
154
154
|
end
|
155
|
-
ext_key.
|
155
|
+
raise ArgumentError, Errors::Messages:: INVALID_BIP32_ZERO_DEPTH if ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_key.depth > 0
|
156
156
|
ext_key.chain_code = buf.read(32)
|
157
|
-
buf.read(1) # 0x00
|
157
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_PRIV_PREFIX unless buf.read(1).bth == '00' # 0x00
|
158
158
|
ext_key.key = Bitcoin::Key.new(priv_key: buf.read(32).bth, key_type: Bitcoin::Key::TYPES[:compressed])
|
159
159
|
ext_key
|
160
160
|
end
|
161
161
|
|
162
162
|
# import private key from Base58 private key address
|
163
|
-
def self.from_base58(
|
164
|
-
ExtKey.parse_from_payload(
|
163
|
+
def self.from_base58(base58)
|
164
|
+
ExtKey.parse_from_payload(ExtPubkey.validate_base58(base58))
|
165
165
|
end
|
166
166
|
|
167
167
|
# get version bytes from purpose' value.
|
@@ -253,9 +253,14 @@ module Bitcoin
|
|
253
253
|
|
254
254
|
# Base58 encoded extended pubkey
|
255
255
|
def to_base58
|
256
|
-
|
257
|
-
|
258
|
-
|
256
|
+
ExtPubkey.encode_base58(to_hex)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Generate Base58 encoded key from BIP32 payload with hex format.
|
260
|
+
# @param [String] hex BIP32 payload with hex format.
|
261
|
+
# @return [String] Base58 encoded extended key.
|
262
|
+
def self.encode_base58(hex)
|
263
|
+
Base58.encode(hex + Bitcoin.calc_checksum(hex))
|
259
264
|
end
|
260
265
|
|
261
266
|
# whether hardened key.
|
@@ -275,7 +280,7 @@ module Bitcoin
|
|
275
280
|
l = Bitcoin.hmac_sha512(chain_code, data)
|
276
281
|
left = l[0..31].bth.to_i(16)
|
277
282
|
raise 'invalid key' if left >= CURVE_ORDER
|
278
|
-
p1 = Bitcoin::
|
283
|
+
p1 = Bitcoin::Key.new(priv_key: left.to_s(16), key_type: Bitcoin::Key::TYPES[:uncompressed]).to_point
|
279
284
|
p2 = Bitcoin::Key.new(pubkey: pubkey, key_type: key_type).to_point
|
280
285
|
new_key.pubkey = (p1 + p2).to_hex
|
281
286
|
new_key.chain_code = l[32..-1]
|
@@ -310,22 +315,33 @@ module Bitcoin
|
|
310
315
|
buf = StringIO.new(payload)
|
311
316
|
ext_pubkey = ExtPubkey.new
|
312
317
|
ext_pubkey.ver = buf.read(4).bth # version
|
313
|
-
raise
|
314
|
-
ext_pubkey.depth = buf.read(1).
|
318
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_VERSION unless ExtPubkey.support_version?(ext_pubkey.ver)
|
319
|
+
ext_pubkey.depth = buf.read(1).unpack1('C')
|
315
320
|
ext_pubkey.parent_fingerprint = buf.read(4).bth
|
321
|
+
ext_pubkey.number = buf.read(4).unpack1('N')
|
316
322
|
if ext_pubkey.depth == 0
|
317
|
-
raise ArgumentError,
|
323
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT unless ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
324
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_pubkey.number > 0
|
318
325
|
end
|
319
|
-
ext_pubkey.
|
326
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH if ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_pubkey.depth > 0
|
320
327
|
ext_pubkey.chain_code = buf.read(32)
|
321
|
-
ext_pubkey.pubkey = buf.read(33).bth
|
328
|
+
ext_pubkey.pubkey = Bitcoin::Key.new(pubkey: buf.read(33).bth).pubkey
|
322
329
|
ext_pubkey
|
323
330
|
end
|
324
331
|
|
325
332
|
|
326
333
|
# import pub key from Base58 private key address
|
327
334
|
def self.from_base58(address)
|
328
|
-
ExtPubkey.parse_from_payload(
|
335
|
+
ExtPubkey.parse_from_payload(ExtPubkey.validate_base58(address))
|
336
|
+
end
|
337
|
+
|
338
|
+
# Validate address checksum and return payload.
|
339
|
+
# @param [String] BIP32 Base58 address
|
340
|
+
# @return [String] BIP32 payload with binary format
|
341
|
+
def self.validate_base58(address)
|
342
|
+
raw = Base58.decode(address)
|
343
|
+
raise ArgumentError, Errors::Messages::INVALID_CHECKSUM unless Bitcoin.calc_checksum(raw[0...-8]) == raw[-8..-1]
|
344
|
+
raw[0...-8].htb
|
329
345
|
end
|
330
346
|
|
331
347
|
# get version bytes from purpose' value.
|