tapyrus 0.1.0 → 0.2.4
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/README.md +7 -15
- data/exe/tapyrusrbd +2 -2
- data/lib/openassets/util.rb +2 -4
- data/lib/schnorr.rb +83 -0
- data/lib/schnorr/signature.rb +38 -0
- data/lib/tapyrus.rb +11 -18
- data/lib/tapyrus/block.rb +3 -38
- data/lib/tapyrus/block_header.rb +70 -41
- data/lib/tapyrus/chain_params.rb +13 -36
- data/lib/tapyrus/chainparams/{regtest.yml → dev.yml} +10 -19
- data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -19
- data/lib/tapyrus/constants.rb +12 -34
- data/lib/tapyrus/errors.rb +17 -0
- data/lib/tapyrus/ext.rb +5 -0
- data/lib/tapyrus/ext/ecdsa.rb +39 -0
- data/lib/tapyrus/ext/json_parser.rb +47 -0
- data/lib/tapyrus/ext_key.rb +42 -23
- data/lib/tapyrus/key.rb +47 -40
- data/lib/tapyrus/message.rb +2 -2
- data/lib/tapyrus/message/base.rb +1 -0
- data/lib/tapyrus/message/block.rb +4 -4
- data/lib/tapyrus/message/cmpct_block.rb +3 -5
- data/lib/tapyrus/message/header_and_short_ids.rb +1 -1
- data/lib/tapyrus/message/headers.rb +1 -1
- data/lib/tapyrus/message/merkle_block.rb +1 -1
- data/lib/tapyrus/message/tx.rb +2 -2
- data/lib/tapyrus/network/peer.rb +1 -15
- data/lib/tapyrus/node/cli.rb +15 -11
- data/lib/tapyrus/node/configuration.rb +1 -1
- data/lib/tapyrus/node/spv.rb +1 -1
- data/lib/tapyrus/opcodes.rb +5 -0
- data/lib/tapyrus/out_point.rb +1 -1
- data/lib/tapyrus/rpc/request_handler.rb +7 -6
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
- data/lib/tapyrus/script/color.rb +79 -0
- data/lib/tapyrus/script/multisig.rb +0 -27
- data/lib/tapyrus/script/script.rb +74 -89
- data/lib/tapyrus/script/script_error.rb +8 -14
- data/lib/tapyrus/script/script_interpreter.rb +65 -86
- data/lib/tapyrus/script/tx_checker.rb +21 -5
- data/lib/tapyrus/secp256k1.rb +1 -0
- data/lib/tapyrus/secp256k1/native.rb +93 -20
- data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
- data/lib/tapyrus/secp256k1/ruby.rb +63 -54
- data/lib/tapyrus/store/chain_entry.rb +3 -2
- data/lib/tapyrus/store/db/level_db.rb +58 -0
- data/lib/tapyrus/store/spv_chain.rb +29 -11
- data/lib/tapyrus/tx.rb +18 -160
- data/lib/tapyrus/tx_in.rb +4 -11
- data/lib/tapyrus/tx_out.rb +2 -1
- data/lib/tapyrus/util.rb +8 -0
- data/lib/tapyrus/validation.rb +1 -6
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +1 -0
- data/lib/tapyrus/wallet/master_key.rb +1 -0
- data/tapyrusrb.gemspec +3 -3
- metadata +44 -39
- data/lib/tapyrus/chainparams/testnet.yml +0 -41
- data/lib/tapyrus/descriptor.rb +0 -147
- data/lib/tapyrus/script_witness.rb +0 -38
data/lib/tapyrus/chain_params.rb
CHANGED
@@ -10,7 +10,8 @@ module Tapyrus
|
|
10
10
|
attr_reader :message_magic
|
11
11
|
attr_reader :address_version
|
12
12
|
attr_reader :p2sh_version
|
13
|
-
attr_reader :
|
13
|
+
attr_reader :cp2pkh_version
|
14
|
+
attr_reader :cp2sh_version
|
14
15
|
attr_reader :privkey_version
|
15
16
|
attr_reader :extended_privkey_version
|
16
17
|
attr_reader :extended_pubkey_version
|
@@ -23,6 +24,7 @@ module Tapyrus
|
|
23
24
|
attr_reader :bip84_pubkey_p2wsh_version
|
24
25
|
attr_reader :bip84_privkey_p2wsh_version
|
25
26
|
attr_reader :default_port
|
27
|
+
attr_reader :rpc_port
|
26
28
|
attr_reader :protocol_version
|
27
29
|
attr_reader :retarget_interval
|
28
30
|
attr_reader :retarget_time
|
@@ -31,51 +33,26 @@ module Tapyrus
|
|
31
33
|
attr_reader :bip34_height
|
32
34
|
attr_reader :proof_of_work_limit
|
33
35
|
attr_reader :dns_seeds
|
34
|
-
attr_reader :genesis
|
35
36
|
attr_reader :bip44_coin_type
|
36
37
|
|
37
38
|
attr_accessor :dust_relay_fee
|
38
39
|
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
# mainnet genesis
|
43
|
-
def self.mainnet
|
44
|
-
init('mainnet')
|
45
|
-
end
|
46
|
-
|
47
|
-
# testnet genesis
|
48
|
-
def self.testnet
|
49
|
-
init('testnet')
|
50
|
-
end
|
51
|
-
|
52
|
-
# regtest genesis
|
53
|
-
def self.regtest
|
54
|
-
init('regtest')
|
55
|
-
end
|
56
|
-
|
57
|
-
def mainnet?
|
58
|
-
network == 'mainnet'
|
59
|
-
end
|
60
|
-
|
61
|
-
def testnet?
|
62
|
-
network == 'testnet'
|
40
|
+
# production genesis
|
41
|
+
def self.prod
|
42
|
+
init('prod')
|
63
43
|
end
|
64
44
|
|
65
|
-
|
66
|
-
|
45
|
+
# development genesis
|
46
|
+
def self.dev
|
47
|
+
init('dev')
|
67
48
|
end
|
68
49
|
|
69
|
-
def
|
70
|
-
|
71
|
-
genesis['version'], genesis['prev_hash'].rhex, genesis['merkle_root'].rhex,
|
72
|
-
genesis['time'], genesis['bits'], genesis['nonce'])
|
73
|
-
Tapyrus::Block.new(header)
|
50
|
+
def prod?
|
51
|
+
network == 'prod'
|
74
52
|
end
|
75
53
|
|
76
|
-
|
77
|
-
|
78
|
-
!fork_id.nil?
|
54
|
+
def dev?
|
55
|
+
network == 'dev'
|
79
56
|
end
|
80
57
|
|
81
58
|
def self.init(name)
|
@@ -1,10 +1,11 @@
|
|
1
1
|
--- !ruby/object:Tapyrus::ChainParams
|
2
|
-
network: "
|
3
|
-
magic_head: "
|
4
|
-
message_magic: "
|
2
|
+
network: "dev"
|
3
|
+
magic_head: "0b110907"
|
4
|
+
message_magic: "Tapyrus Signed Message:\n"
|
5
5
|
address_version: "6f"
|
6
6
|
p2sh_version: "c4"
|
7
|
-
|
7
|
+
cp2pkh_version: "70"
|
8
|
+
cp2sh_version: "c5"
|
8
9
|
privkey_version: "ef"
|
9
10
|
extended_privkey_version: "04358394"
|
10
11
|
extended_pubkey_version: "043587cf"
|
@@ -16,23 +17,13 @@ bip84_pubkey_p2wpkh_version: "045f1cf6"
|
|
16
17
|
bip84_pubkey_p2wsh_version: "02575483"
|
17
18
|
bip84_privkey_p2wpkh_version: "045f18bc"
|
18
19
|
bip84_privkey_p2wsh_version: "02575048"
|
19
|
-
default_port:
|
20
|
-
|
20
|
+
default_port: 12383
|
21
|
+
rpc_port: 12381
|
22
|
+
protocol_version: 10000
|
21
23
|
retarget_interval: 2016
|
22
24
|
retarget_time: 1209600 # 2 weeks
|
23
25
|
target_spacing: 600 # block interval
|
24
26
|
max_money: 21000000
|
25
|
-
bip34_height:
|
26
|
-
genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
27
|
-
proof_of_work_limit: 0x207fffff
|
27
|
+
bip34_height: 227931
|
28
28
|
dns_seeds:
|
29
|
-
|
30
|
-
hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
31
|
-
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
32
|
-
time: 1296688602
|
33
|
-
nonce: 2
|
34
|
-
bits: 0x207fffff
|
35
|
-
version: 1
|
36
|
-
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
37
|
-
bip44_coin_type: 1
|
38
|
-
dust_relay_fee: 3600
|
29
|
+
bip44_coin_type: 1
|
@@ -1,10 +1,11 @@
|
|
1
1
|
--- !ruby/object:Tapyrus::ChainParams
|
2
|
-
network: "
|
2
|
+
network: "prod"
|
3
3
|
magic_head: "f9beb4d9"
|
4
|
-
message_magic: "
|
4
|
+
message_magic: "Tapyrus Signed Message:\n"
|
5
5
|
address_version: "00"
|
6
6
|
p2sh_version: "05"
|
7
|
-
|
7
|
+
cp2pkh_version: "01"
|
8
|
+
cp2sh_version: "06"
|
8
9
|
privkey_version: "80"
|
9
10
|
extended_privkey_version: "0488ade4"
|
10
11
|
extended_pubkey_version: "0488b21e"
|
@@ -16,26 +17,13 @@ bip84_pubkey_p2wpkh_version: "04b24746"
|
|
16
17
|
bip84_pubkey_p2wsh_version: "02aa7ed3"
|
17
18
|
bip84_privkey_p2wpkh_version: "04b2430c"
|
18
19
|
bip84_privkey_p2wsh_version: "02aa7a99"
|
19
|
-
default_port:
|
20
|
-
|
20
|
+
default_port: 2357
|
21
|
+
rpc_port: 2377
|
22
|
+
protocol_version: 10000
|
21
23
|
retarget_interval: 2016
|
22
24
|
retarget_time: 1209600 # 2 weeks
|
23
25
|
target_spacing: 600 # block interval
|
24
26
|
max_money: 21000000
|
25
27
|
bip34_height: 227931
|
26
|
-
proof_of_work_limit: 0x1d00ffff
|
27
28
|
dns_seeds:
|
28
|
-
- "seed.bitcoin.sipa.be"
|
29
|
-
- "dnsseed.bluematt.me"
|
30
|
-
- "dnsseed.bitcoin.dashjr.org"
|
31
|
-
- "seed.bitcoinstats.com"
|
32
|
-
- "seed.bitcoin.jonasschnelli.ch"
|
33
|
-
genesis:
|
34
|
-
hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
35
|
-
merkle_root: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
36
|
-
time: 1231006505
|
37
|
-
nonce: 2083236893
|
38
|
-
bits: 0x1d00ffff
|
39
|
-
version: 1
|
40
|
-
prev_hash: "0000000000000000000000000000000000000000000000000000000000000000"
|
41
29
|
bip44_coin_type: 0
|
data/lib/tapyrus/constants.rb
CHANGED
@@ -38,11 +38,8 @@ module Tapyrus
|
|
38
38
|
SCRIPT_VERIFY_CLEANSTACK = (1 << 8)
|
39
39
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9) # Verify CHECKLOCKTIMEVERIFY (BIP-65)
|
40
40
|
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1 << 10) # support CHECKSEQUENCEVERIFY opcode (BIP-112)
|
41
|
-
SCRIPT_VERIFY_WITNESS = (1 << 11) # Support segregated witness
|
42
|
-
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1 << 12) # Making v1-v16 witness program non-standard
|
43
41
|
SCRIPT_VERIFY_MINIMALIF = (1 << 13) # Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
|
44
42
|
SCRIPT_VERIFY_NULLFAIL = (1 << 14) # Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
|
45
|
-
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1 << 15) # Public keys in segregated witness scripts must be compressed
|
46
43
|
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1 << 16) # Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
47
44
|
|
48
45
|
MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH
|
@@ -60,16 +57,10 @@ module Tapyrus
|
|
60
57
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
|
61
58
|
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
|
62
59
|
SCRIPT_VERIFY_LOW_S,
|
63
|
-
SCRIPT_VERIFY_WITNESS,
|
64
|
-
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
|
65
|
-
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
|
66
60
|
SCRIPT_VERIFY_CONST_SCRIPTCODE].inject(SCRIPT_VERIFY_NONE){|flags, f| flags |= f}
|
67
61
|
|
68
62
|
# for script
|
69
63
|
|
70
|
-
# witness version
|
71
|
-
WITNESS_VERSION = 0x00
|
72
|
-
|
73
64
|
# Maximum script length in bytes
|
74
65
|
MAX_SCRIPT_SIZE = 10000
|
75
66
|
|
@@ -91,20 +82,13 @@ module Tapyrus
|
|
91
82
|
# Signature hash types/flags
|
92
83
|
SIGHASH_TYPE = { all: 1, none: 2, single: 3, anyonecanpay: 128 }
|
93
84
|
|
94
|
-
# SIGHASH_FORK_ID for replay protection of the fork coin
|
95
|
-
SIGHASH_FORK_ID = 0x40
|
96
|
-
|
97
|
-
# fork coin id.
|
98
|
-
FORK_ID_CASH = 0
|
99
|
-
FORK_ID_GOLD = 79
|
100
|
-
|
101
85
|
# Maximum number length in bytes
|
102
86
|
DEFAULT_MAX_NUM_SIZE = 4
|
103
87
|
|
104
88
|
# 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes.
|
105
89
|
MAX_OP_RETURN_RELAY = 83
|
106
90
|
|
107
|
-
SIG_VERSION = [:base
|
91
|
+
SIG_VERSION = [:base]
|
108
92
|
|
109
93
|
# for script error
|
110
94
|
SCRIPT_ERR_OK = 0
|
@@ -126,6 +110,7 @@ module Tapyrus
|
|
126
110
|
SCRIPT_ERR_CHECKMULTISIGVERIFY = 22
|
127
111
|
SCRIPT_ERR_CHECKSIGVERIFY = 23
|
128
112
|
SCRIPT_ERR_NUMEQUALVERIFY = 24
|
113
|
+
SCRIPT_ERR_CHECKDATASIGVERIFY = 25
|
129
114
|
|
130
115
|
# Logical/Format/Canonical errors
|
131
116
|
SCRIPT_ERR_BAD_OPCODE = 30
|
@@ -133,6 +118,7 @@ module Tapyrus
|
|
133
118
|
SCRIPT_ERR_INVALID_STACK_OPERATION = 32
|
134
119
|
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION = 33
|
135
120
|
SCRIPT_ERR_UNBALANCED_CONDITIONAL = 34
|
121
|
+
SCRIPT_ERR_MIXED_SCHEME_MULTISIG = 35
|
136
122
|
|
137
123
|
# CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY
|
138
124
|
SCRIPT_ERR_NEGATIVE_LOCKTIME = 40
|
@@ -146,35 +132,27 @@ module Tapyrus
|
|
146
132
|
SCRIPT_ERR_SIG_HIGH_S = 54
|
147
133
|
SCRIPT_ERR_SIG_NULLDUMMY = 55
|
148
134
|
SCRIPT_ERR_PUBKEYTYPE = 56
|
149
|
-
SCRIPT_ERR_CLEANSTACK =
|
150
|
-
SCRIPT_ERR_MINIMALIF =
|
151
|
-
SCRIPT_ERR_SIG_NULLFAIL =
|
135
|
+
SCRIPT_ERR_CLEANSTACK = 57
|
136
|
+
SCRIPT_ERR_MINIMALIF = 58
|
137
|
+
SCRIPT_ERR_SIG_NULLFAIL = 59
|
152
138
|
|
153
139
|
# softfork safeness
|
154
140
|
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS = 60
|
155
|
-
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = 61
|
156
|
-
|
157
|
-
# segregated witness
|
158
|
-
SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH = 70
|
159
|
-
SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY = 71
|
160
|
-
SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH = 72
|
161
|
-
SCRIPT_ERR_WITNESS_MALLEATED = 73
|
162
|
-
SCRIPT_ERR_WITNESS_MALLEATED_P2SH = 74
|
163
|
-
SCRIPT_ERR_WITNESS_UNEXPECTED = 75
|
164
|
-
SCRIPT_ERR_WITNESS_PUBKEYTYPE = 76
|
165
141
|
|
166
142
|
# Constant scriptCode
|
167
143
|
SCRIPT_ERR_OP_CODESEPARATOR = 77
|
168
144
|
SCRIPT_ERR_SIG_FINDANDDELETE = 78
|
169
145
|
|
170
|
-
|
146
|
+
SCRIPT_ERR_OP_COLOR_UNEXPECTED = 79
|
147
|
+
SCRIPT_ERR_OP_COLOR_ID_INVALID = 80
|
148
|
+
SCRIPT_ERR_OP_COLOR_MULTIPLE = 81
|
149
|
+
SCRIPT_ERR_OP_COLOR_IN_BRANCH = 82
|
150
|
+
|
151
|
+
SCRIPT_ERR_ERROR_COUNT = 83
|
171
152
|
|
172
153
|
ERRCODES_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [const_get(c), c.to_s] }.flatten]
|
173
154
|
NAME_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
174
155
|
|
175
|
-
# witness commitment
|
176
|
-
WITNESS_COMMITMENT_HEADER = 'aa21a9ed'
|
177
|
-
|
178
156
|
COINBASE_WTXID = '00'* 32
|
179
157
|
|
180
158
|
# for message
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
module Errors
|
3
|
+
module Messages
|
4
|
+
|
5
|
+
INVALID_PUBLIC_KEY = 'Invalid public key.'
|
6
|
+
INVALID_BIP32_PRIV_PREFIX = 'Invalid BIP32 private key prefix. prefix must be 0x00.'
|
7
|
+
INVALID_BIP32_FINGERPRINT = 'Invalid parent fingerprint.'
|
8
|
+
INVALID_BIP32_ZERO_INDEX = 'Invalid index. Depth 0 must have 0 index.'
|
9
|
+
INVALID_BIP32_ZERO_DEPTH = 'Invalid depth. Master key must have 0 depth.'
|
10
|
+
INVALID_BIP32_VERSION = 'An unsupported version byte was specified.'
|
11
|
+
|
12
|
+
INVALID_PRIV_KEY = 'Private key is not in range [1..n-1].'
|
13
|
+
INVALID_CHECKSUM = 'Invalid checksum.'
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/tapyrus/ext.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class ::ECDSA::Signature
|
2
|
+
# convert signature to der string.
|
3
|
+
def to_der
|
4
|
+
ECDSA::Format::SignatureDerString.encode(self)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class ::ECDSA::Point
|
9
|
+
def to_hex(compression = true)
|
10
|
+
ECDSA::Format::PointOctetString.encode(self, compression: compression).bth
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ::ECDSA::Format::PointOctetString
|
15
|
+
|
16
|
+
def self.decode(string, group, allow_hybrid: false)
|
17
|
+
string = string.dup.force_encoding('BINARY')
|
18
|
+
|
19
|
+
raise ECDSA::Format::DecodeError, 'Point octet string is empty.' if string.empty?
|
20
|
+
|
21
|
+
case string[0].ord
|
22
|
+
when 0
|
23
|
+
check_length string, 1
|
24
|
+
return group.infinity
|
25
|
+
when 2
|
26
|
+
decode_compressed string, group, 0
|
27
|
+
when 3
|
28
|
+
decode_compressed string, group, 1
|
29
|
+
when 4
|
30
|
+
decode_uncompressed string, group
|
31
|
+
when 6..7
|
32
|
+
raise DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord unless allow_hybrid
|
33
|
+
decode_uncompressed string, group if allow_hybrid
|
34
|
+
else
|
35
|
+
raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'json/pure'
|
2
|
+
|
3
|
+
module Tapyrus
|
4
|
+
module Ext
|
5
|
+
|
6
|
+
# Extension of JSON::Pure::Parser.
|
7
|
+
# This class convert Float value to String value.
|
8
|
+
class JsonParser < JSON::Pure::Parser
|
9
|
+
|
10
|
+
def parse_value
|
11
|
+
case
|
12
|
+
when scan(FLOAT)
|
13
|
+
self[1].to_s
|
14
|
+
when scan(INTEGER)
|
15
|
+
Integer(self[1])
|
16
|
+
when scan(TRUE)
|
17
|
+
true
|
18
|
+
when scan(FALSE)
|
19
|
+
false
|
20
|
+
when scan(NULL)
|
21
|
+
nil
|
22
|
+
when !UNPARSED.equal?(string = parse_string)
|
23
|
+
string
|
24
|
+
when scan(ARRAY_OPEN)
|
25
|
+
@current_nesting += 1
|
26
|
+
ary = parse_array
|
27
|
+
@current_nesting -= 1
|
28
|
+
ary
|
29
|
+
when scan(OBJECT_OPEN)
|
30
|
+
@current_nesting += 1
|
31
|
+
obj = parse_object
|
32
|
+
@current_nesting -= 1
|
33
|
+
obj
|
34
|
+
when @allow_nan && scan(NAN)
|
35
|
+
NaN
|
36
|
+
when @allow_nan && scan(INFINITY)
|
37
|
+
Infinity
|
38
|
+
when @allow_nan && scan(MINUS_INFINITY)
|
39
|
+
MinusInfinity
|
40
|
+
else
|
41
|
+
UNPARSED
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/tapyrus/ext_key.rb
CHANGED
@@ -5,6 +5,10 @@ module Tapyrus
|
|
5
5
|
|
6
6
|
# BIP32 Extended private key
|
7
7
|
class ExtKey
|
8
|
+
include Tapyrus::HexConverter
|
9
|
+
|
10
|
+
MAX_DEPTH = 255
|
11
|
+
MASTER_FINGERPRINT = '00000000'
|
8
12
|
|
9
13
|
attr_accessor :ver
|
10
14
|
attr_accessor :depth
|
@@ -19,7 +23,7 @@ module Tapyrus
|
|
19
23
|
ext_key = ExtKey.new
|
20
24
|
ext_key.depth = ext_key.number = 0
|
21
25
|
ext_key.parent_fingerprint = '00000000'
|
22
|
-
l = Tapyrus.hmac_sha512('
|
26
|
+
l = Tapyrus.hmac_sha512('Tapyrus seed', seed.htb)
|
23
27
|
left = l[0..31].bth.to_i(16)
|
24
28
|
raise 'invalid key' if left >= CURVE_ORDER || left == 0
|
25
29
|
ext_key.key = Tapyrus::Key.new(priv_key: l[0..31].bth, key_type: Tapyrus::Key::TYPES[:compressed])
|
@@ -47,9 +51,7 @@ module Tapyrus
|
|
47
51
|
|
48
52
|
# Base58 encoded extended private key
|
49
53
|
def to_base58
|
50
|
-
|
51
|
-
hex = h + Tapyrus.calc_checksum(h)
|
52
|
-
Base58.encode(hex)
|
54
|
+
ExtPubkey.encode_base58(to_hex)
|
53
55
|
end
|
54
56
|
|
55
57
|
# get private key(hex)
|
@@ -140,19 +142,24 @@ module Tapyrus
|
|
140
142
|
buf = StringIO.new(payload)
|
141
143
|
ext_key = ExtKey.new
|
142
144
|
ext_key.ver = buf.read(4).bth # version
|
143
|
-
raise
|
145
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_VERSION unless ExtKey.support_version?(ext_key.ver)
|
144
146
|
ext_key.depth = buf.read(1).unpack('C').first
|
145
147
|
ext_key.parent_fingerprint = buf.read(4).bth
|
146
148
|
ext_key.number = buf.read(4).unpack('N').first
|
149
|
+
if ext_key.depth == 0
|
150
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT unless ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
151
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_key.number > 0
|
152
|
+
end
|
153
|
+
raise ArgumentError, Errors::Messages:: INVALID_BIP32_ZERO_DEPTH if ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_key.depth > 0
|
147
154
|
ext_key.chain_code = buf.read(32)
|
148
|
-
buf.read(1) # 0x00
|
155
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_PRIV_PREFIX unless buf.read(1).bth == '00' # 0x00
|
149
156
|
ext_key.key = Tapyrus::Key.new(priv_key: buf.read(32).bth, key_type: Tapyrus::Key::TYPES[:compressed])
|
150
157
|
ext_key
|
151
158
|
end
|
152
159
|
|
153
160
|
# import private key from Base58 private key address
|
154
161
|
def self.from_base58(address)
|
155
|
-
ExtKey.parse_from_payload(
|
162
|
+
ExtKey.parse_from_payload(ExtPubkey.validate_checksum(address))
|
156
163
|
end
|
157
164
|
|
158
165
|
# get version bytes from purpose' value.
|
@@ -190,6 +197,7 @@ module Tapyrus
|
|
190
197
|
|
191
198
|
# BIP-32 Extended public key
|
192
199
|
class ExtPubkey
|
200
|
+
include Tapyrus::HexConverter
|
193
201
|
|
194
202
|
attr_accessor :ver
|
195
203
|
attr_accessor :depth
|
@@ -214,14 +222,7 @@ module Tapyrus
|
|
214
222
|
|
215
223
|
# get address
|
216
224
|
def addr
|
217
|
-
|
218
|
-
when Tapyrus.chain_params.bip49_pubkey_p2wpkh_p2sh_version
|
219
|
-
key.to_nested_p2wpkh
|
220
|
-
when Tapyrus.chain_params.bip84_pubkey_p2wpkh_version
|
221
|
-
key.to_p2wpkh
|
222
|
-
else
|
223
|
-
key.to_p2pkh
|
224
|
-
end
|
225
|
+
key.to_p2pkh
|
225
226
|
end
|
226
227
|
|
227
228
|
# get key object
|
@@ -242,9 +243,14 @@ module Tapyrus
|
|
242
243
|
|
243
244
|
# Base58 encoded extended pubkey
|
244
245
|
def to_base58
|
245
|
-
|
246
|
-
|
247
|
-
|
246
|
+
ExtPubkey.encode_base58(to_hex)
|
247
|
+
end
|
248
|
+
|
249
|
+
# Generate Base58 encoded key from BIP32 payload with hex format.
|
250
|
+
# @param [String] hex BIP32 payload with hex format.
|
251
|
+
# @return [String] Base58 encoded extended key.
|
252
|
+
def self.encode_base58(hex)
|
253
|
+
Base58.encode(hex + Tapyrus.calc_checksum(hex))
|
248
254
|
end
|
249
255
|
|
250
256
|
# whether hardened key.
|
@@ -265,7 +271,7 @@ module Tapyrus
|
|
265
271
|
raise 'invalid key' if left >= CURVE_ORDER
|
266
272
|
p1 = Tapyrus::Secp256k1::GROUP.generator.multiply_by_scalar(left)
|
267
273
|
p2 = Tapyrus::Key.new(pubkey: pubkey, key_type: key_type).to_point
|
268
|
-
new_key.pubkey =
|
274
|
+
new_key.pubkey = (p1 + p2).to_hex
|
269
275
|
new_key.chain_code = l[32..-1]
|
270
276
|
new_key.ver = version
|
271
277
|
new_key
|
@@ -298,19 +304,32 @@ module Tapyrus
|
|
298
304
|
buf = StringIO.new(payload)
|
299
305
|
ext_pubkey = ExtPubkey.new
|
300
306
|
ext_pubkey.ver = buf.read(4).bth # version
|
301
|
-
raise
|
307
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_VERSION unless ExtPubkey.support_version?(ext_pubkey.ver)
|
302
308
|
ext_pubkey.depth = buf.read(1).unpack('C').first
|
303
309
|
ext_pubkey.parent_fingerprint = buf.read(4).bth
|
304
310
|
ext_pubkey.number = buf.read(4).unpack('N').first
|
311
|
+
if ext_pubkey.depth == 0
|
312
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT unless ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
313
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_pubkey.number > 0
|
314
|
+
end
|
315
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH if ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_pubkey.depth > 0
|
305
316
|
ext_pubkey.chain_code = buf.read(32)
|
306
|
-
ext_pubkey.pubkey = buf.read(33).bth
|
317
|
+
ext_pubkey.pubkey = Tapyrus::Key.new(pubkey: buf.read(33).bth).pubkey
|
307
318
|
ext_pubkey
|
308
319
|
end
|
309
320
|
|
310
|
-
|
311
321
|
# import pub key from Base58 private key address
|
312
322
|
def self.from_base58(address)
|
313
|
-
ExtPubkey.parse_from_payload(
|
323
|
+
ExtPubkey.parse_from_payload(ExtPubkey.validate_checksum(address))
|
324
|
+
end
|
325
|
+
|
326
|
+
# Validate address checksum and return payload.
|
327
|
+
# @param [String] BIP32 Base58 address
|
328
|
+
# @return [String] BIP32 payload with binary format
|
329
|
+
def self.validate_checksum(base58)
|
330
|
+
raw = Base58.decode(base58)
|
331
|
+
raise ArgumentError, Errors::Messages::INVALID_CHECKSUM unless Tapyrus.calc_checksum(raw[0...-8]) == raw[-8..-1]
|
332
|
+
raw[0...-8].htb
|
314
333
|
end
|
315
334
|
|
316
335
|
# get version bytes from purpose' value.
|