tapyrus 0.2.7 → 0.2.8
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/.prettierignore +3 -0
- data/.prettierrc.yaml +3 -0
- data/CODE_OF_CONDUCT.md +7 -7
- data/README.md +14 -17
- data/Rakefile +3 -3
- data/lib/openassets.rb +0 -2
- data/lib/openassets/marker_output.rb +0 -4
- data/lib/openassets/payload.rb +4 -10
- data/lib/schnorr.rb +2 -3
- data/lib/schnorr/signature.rb +3 -6
- data/lib/tapyrus.rb +6 -22
- data/lib/tapyrus/base58.rb +7 -6
- data/lib/tapyrus/block.rb +1 -2
- data/lib/tapyrus/block_header.rb +15 -9
- data/lib/tapyrus/bloom_filter.rb +5 -3
- data/lib/tapyrus/chain_params.rb +1 -4
- data/lib/tapyrus/chainparams/dev.yml +3 -2
- data/lib/tapyrus/chainparams/prod.yml +3 -2
- data/lib/tapyrus/constants.rb +29 -23
- data/lib/tapyrus/errors.rb +1 -3
- data/lib/tapyrus/ext.rb +1 -1
- data/lib/tapyrus/ext/ecdsa.rb +4 -4
- data/lib/tapyrus/ext/json_parser.rb +1 -4
- data/lib/tapyrus/ext_key.rb +38 -34
- data/lib/tapyrus/key.rb +31 -35
- data/lib/tapyrus/key_path.rb +15 -12
- data/lib/tapyrus/logger.rb +20 -16
- data/lib/tapyrus/merkle_tree.rb +19 -20
- data/lib/tapyrus/message.rb +14 -16
- data/lib/tapyrus/message/addr.rb +1 -7
- data/lib/tapyrus/message/base.rb +0 -3
- data/lib/tapyrus/message/block.rb +2 -9
- data/lib/tapyrus/message/block_transaction_request.rb +3 -6
- data/lib/tapyrus/message/block_transactions.rb +2 -6
- data/lib/tapyrus/message/block_txn.rb +0 -4
- data/lib/tapyrus/message/cmpct_block.rb +1 -7
- data/lib/tapyrus/message/error.rb +1 -4
- data/lib/tapyrus/message/fee_filter.rb +1 -4
- data/lib/tapyrus/message/filter_add.rb +0 -4
- data/lib/tapyrus/message/filter_clear.rb +0 -4
- data/lib/tapyrus/message/filter_load.rb +2 -5
- data/lib/tapyrus/message/get_addr.rb +0 -4
- data/lib/tapyrus/message/get_block_txn.rb +0 -4
- data/lib/tapyrus/message/get_blocks.rb +0 -3
- data/lib/tapyrus/message/get_data.rb +1 -4
- data/lib/tapyrus/message/get_headers.rb +1 -3
- data/lib/tapyrus/message/header_and_short_ids.rb +3 -9
- data/lib/tapyrus/message/headers.rb +0 -4
- data/lib/tapyrus/message/headers_parser.rb +3 -8
- data/lib/tapyrus/message/inv.rb +1 -4
- data/lib/tapyrus/message/inventories_parser.rb +2 -7
- data/lib/tapyrus/message/inventory.rb +12 -5
- data/lib/tapyrus/message/mem_pool.rb +0 -4
- data/lib/tapyrus/message/merkle_block.rb +4 -9
- data/lib/tapyrus/message/network_addr.rb +7 -6
- data/lib/tapyrus/message/not_found.rb +0 -3
- data/lib/tapyrus/message/ping.rb +0 -3
- data/lib/tapyrus/message/pong.rb +0 -3
- data/lib/tapyrus/message/prefilled_tx.rb +0 -4
- data/lib/tapyrus/message/reject.rb +0 -3
- data/lib/tapyrus/message/send_cmpct.rb +1 -3
- data/lib/tapyrus/message/send_headers.rb +0 -3
- data/lib/tapyrus/message/tx.rb +0 -4
- data/lib/tapyrus/message/ver_ack.rb +1 -5
- data/lib/tapyrus/message/version.rb +2 -5
- data/lib/tapyrus/mnemonic.rb +17 -15
- data/lib/tapyrus/network.rb +0 -2
- data/lib/tapyrus/network/connection.rb +0 -3
- data/lib/tapyrus/network/message_handler.rb +61 -60
- data/lib/tapyrus/network/peer.rb +13 -12
- data/lib/tapyrus/network/peer_discovery.rb +3 -5
- data/lib/tapyrus/network/pool.rb +12 -12
- data/lib/tapyrus/node.rb +1 -1
- data/lib/tapyrus/node/cli.rb +12 -14
- data/lib/tapyrus/node/configuration.rb +1 -3
- data/lib/tapyrus/node/spv.rb +2 -3
- data/lib/tapyrus/opcodes.rb +9 -7
- data/lib/tapyrus/out_point.rb +5 -5
- data/lib/tapyrus/rpc/http_server.rb +21 -22
- data/lib/tapyrus/rpc/request_handler.rb +42 -44
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +53 -25
- data/lib/tapyrus/script/color.rb +10 -0
- data/lib/tapyrus/script/multisig.rb +13 -12
- data/lib/tapyrus/script/script.rb +72 -71
- data/lib/tapyrus/script/script_error.rb +1 -4
- data/lib/tapyrus/script/script_interpreter.rb +439 -399
- data/lib/tapyrus/script/tx_checker.rb +20 -10
- data/lib/tapyrus/secp256k1.rb +0 -4
- data/lib/tapyrus/secp256k1/native.rb +14 -15
- data/lib/tapyrus/secp256k1/rfc6979.rb +7 -4
- data/lib/tapyrus/secp256k1/ruby.rb +10 -12
- data/lib/tapyrus/slip39.rb +20 -5
- data/lib/tapyrus/slip39/share.rb +41 -29
- data/lib/tapyrus/slip39/sss.rb +101 -57
- data/lib/tapyrus/store.rb +1 -3
- data/lib/tapyrus/store/chain_entry.rb +0 -4
- data/lib/tapyrus/store/db.rb +0 -2
- data/lib/tapyrus/store/db/level_db.rb +5 -9
- data/lib/tapyrus/store/spv_chain.rb +11 -17
- data/lib/tapyrus/tx.rb +45 -37
- data/lib/tapyrus/tx_builder.rb +158 -0
- data/lib/tapyrus/tx_in.rb +1 -6
- data/lib/tapyrus/tx_out.rb +2 -7
- data/lib/tapyrus/util.rb +7 -9
- data/lib/tapyrus/validation.rb +12 -11
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +22 -18
- data/lib/tapyrus/wallet/base.rb +12 -9
- data/lib/tapyrus/wallet/db.rb +6 -9
- data/lib/tapyrus/wallet/master_key.rb +2 -4
- data/tapyrusrb.gemspec +13 -14
- metadata +21 -4
- data/.travis.yml +0 -14
data/lib/tapyrus/bloom_filter.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'murmurhash3'
|
2
2
|
module Tapyrus
|
3
3
|
class BloomFilter
|
4
4
|
LN2_SQUARED = 0.4804530139182014246671025263266649717305529515945455 # log(2) ** 2
|
@@ -23,6 +23,7 @@ module Tapyrus
|
|
23
23
|
# The size S of the filter in bytes is given by (-1 / pow(log(2), 2) * N * log(P)) / 8
|
24
24
|
len = [[(-elements_length * Math.log(fp_rate) / (LN2_SQUARED * 8)).to_i, MAX_BLOOM_FILTER_SIZE].min, 1].max
|
25
25
|
filter = Array.new(len, 0)
|
26
|
+
|
26
27
|
# The number of hash functions required is given by S * 8 / N * log(2)
|
27
28
|
hash_funcs = [[(filter.size * 8 * LN2 / elements_length).to_i, MAX_HASH_FUNCS].min, 1].max
|
28
29
|
BloomFilter.new(filter, hash_funcs, tweak)
|
@@ -59,8 +60,9 @@ module Tapyrus
|
|
59
60
|
end
|
60
61
|
|
61
62
|
private
|
63
|
+
|
62
64
|
def to_hash(data, i)
|
63
|
-
MurmurHash3::V32.str_hash(data, (i * 0xfba4c795 + tweak) & 0xffffffff)
|
65
|
+
MurmurHash3::V32.str_hash(data, (i * 0xfba4c795 + tweak) & 0xffffffff) % (filter.length * 8)
|
64
66
|
end
|
65
67
|
|
66
68
|
def set_bit(data)
|
@@ -72,7 +74,7 @@ module Tapyrus
|
|
72
74
|
end
|
73
75
|
|
74
76
|
def full?
|
75
|
-
@full |= filter.all? {|byte| byte == 0xff}
|
77
|
+
@full |= filter.all? { |byte| byte == 0xff }
|
76
78
|
end
|
77
79
|
end
|
78
80
|
end
|
data/lib/tapyrus/chain_params.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
3
|
module Tapyrus
|
4
|
-
|
5
4
|
# Network parameter class
|
6
5
|
class ChainParams
|
7
|
-
|
8
6
|
attr_reader :network
|
9
7
|
attr_reader :magic_head
|
10
8
|
attr_reader :message_magic
|
@@ -63,5 +61,4 @@ module Tapyrus
|
|
63
61
|
|
64
62
|
private_class_method :init
|
65
63
|
end
|
66
|
-
|
67
|
-
end
|
64
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
---
|
1
|
+
---
|
2
|
+
!ruby/object:Tapyrus::ChainParams
|
2
3
|
network: "dev"
|
3
4
|
magic_head: "0b110907"
|
4
5
|
message_magic: "Tapyrus Signed Message:\n"
|
@@ -26,4 +27,4 @@ target_spacing: 600 # block interval
|
|
26
27
|
max_money: 21000000
|
27
28
|
bip34_height: 227931
|
28
29
|
dns_seeds:
|
29
|
-
bip44_coin_type: 1
|
30
|
+
bip44_coin_type: 1
|
@@ -1,4 +1,5 @@
|
|
1
|
-
---
|
1
|
+
---
|
2
|
+
!ruby/object:Tapyrus::ChainParams
|
2
3
|
network: "prod"
|
3
4
|
magic_head: "f9beb4d9"
|
4
5
|
message_magic: "Tapyrus Signed Message:\n"
|
@@ -26,4 +27,4 @@ target_spacing: 600 # block interval
|
|
26
27
|
max_money: 21000000
|
27
28
|
bip34_height: 227931
|
28
29
|
dns_seeds:
|
29
|
-
bip44_coin_type: 0
|
30
|
+
bip44_coin_type: 0
|
data/lib/tapyrus/constants.rb
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
module Tapyrus
|
2
|
-
|
3
2
|
COIN = 100_000_000
|
4
3
|
MAX_MONEY = 21_000_000 * COIN
|
5
4
|
|
6
5
|
# The maximum allowed size for a serialized block, in bytes (only for buffer size limits)
|
7
6
|
MAX_BLOCK_SERIALIZED_SIZE = 4_000_000
|
7
|
+
|
8
8
|
# The maximum allowed weight for a block, see BIP 141 (network rule)
|
9
9
|
MAX_BLOCK_WEIGHT = 4_000_000
|
10
|
+
|
10
11
|
# The maximum allowed number of signature check operations in a block (network rule)
|
11
12
|
MAX_BLOCK_SIGOPS_COST = 80_000
|
13
|
+
|
12
14
|
# Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
|
13
15
|
COINBASE_MATURITY = 100
|
14
16
|
WITNESS_SCALE_FACTOR = 4
|
15
17
|
|
16
18
|
# 60 is the lower bound for the size of a valid serialized Tx
|
17
19
|
MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60
|
20
|
+
|
18
21
|
# 10 is the lower bound for the size of a serialized Tx
|
19
22
|
MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10
|
20
23
|
|
@@ -26,11 +29,11 @@ module Tapyrus
|
|
26
29
|
DUST_RELAY_TX_FEE = 3000
|
27
30
|
|
28
31
|
# script verify flags
|
29
|
-
SCRIPT_VERIFY_NONE
|
30
|
-
SCRIPT_VERIFY_P2SH
|
32
|
+
SCRIPT_VERIFY_NONE = 0
|
33
|
+
SCRIPT_VERIFY_P2SH = (1 << 0)
|
31
34
|
SCRIPT_VERIFY_STRICTENC = (1 << 1)
|
32
|
-
SCRIPT_VERIFY_DERSIG
|
33
|
-
SCRIPT_VERIFY_LOW_S
|
35
|
+
SCRIPT_VERIFY_DERSIG = (1 << 2)
|
36
|
+
SCRIPT_VERIFY_LOW_S = (1 << 3)
|
34
37
|
SCRIPT_VERIFY_NULLDUMMY = (1 << 4)
|
35
38
|
SCRIPT_VERIFY_SIGPUSHONLY = (1 << 5)
|
36
39
|
SCRIPT_VERIFY_MINIMALDATA = (1 << 6)
|
@@ -45,24 +48,27 @@ module Tapyrus
|
|
45
48
|
MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH
|
46
49
|
|
47
50
|
# Standard script verification flags that standard transactions will comply with.
|
48
|
-
STANDARD_SCRIPT_VERIFY_FLAGS =
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
51
|
+
STANDARD_SCRIPT_VERIFY_FLAGS =
|
52
|
+
[
|
53
|
+
MANDATORY_SCRIPT_VERIFY_FLAGS,
|
54
|
+
SCRIPT_VERIFY_DERSIG,
|
55
|
+
SCRIPT_VERIFY_STRICTENC,
|
56
|
+
SCRIPT_VERIFY_MINIMALDATA,
|
57
|
+
SCRIPT_VERIFY_NULLDUMMY,
|
58
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
|
59
|
+
SCRIPT_VERIFY_CLEANSTACK,
|
60
|
+
SCRIPT_VERIFY_MINIMALIF,
|
61
|
+
SCRIPT_VERIFY_NULLFAIL,
|
62
|
+
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
|
63
|
+
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
|
64
|
+
SCRIPT_VERIFY_LOW_S,
|
65
|
+
SCRIPT_VERIFY_CONST_SCRIPTCODE
|
66
|
+
].inject(SCRIPT_VERIFY_NONE) { |flags, f| flags |= f }
|
61
67
|
|
62
68
|
# for script
|
63
69
|
|
64
70
|
# Maximum script length in bytes
|
65
|
-
MAX_SCRIPT_SIZE =
|
71
|
+
MAX_SCRIPT_SIZE = 10_000
|
66
72
|
|
67
73
|
# Maximum number of public keys per multisig
|
68
74
|
MAX_PUBKEYS_PER_MULTISIG = 20
|
@@ -77,7 +83,7 @@ module Tapyrus
|
|
77
83
|
MAX_STACK_SIZE = 1000
|
78
84
|
|
79
85
|
# Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
|
80
|
-
LOCKTIME_THRESHOLD =
|
86
|
+
LOCKTIME_THRESHOLD = 500_000_000
|
81
87
|
|
82
88
|
# Signature hash types/flags
|
83
89
|
SIGHASH_TYPE = { all: 1, none: 2, single: 3, anyonecanpay: 128 }
|
@@ -153,7 +159,7 @@ module Tapyrus
|
|
153
159
|
ERRCODES_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [const_get(c), c.to_s] }.flatten]
|
154
160
|
NAME_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
155
161
|
|
156
|
-
COINBASE_WTXID = '00'* 32
|
162
|
+
COINBASE_WTXID = '00' * 32
|
157
163
|
|
158
164
|
# for message
|
159
165
|
MESSAGE_HEADER_SIZE = 24
|
@@ -169,5 +175,5 @@ module Tapyrus
|
|
169
175
|
|
170
176
|
BIP32_EXTKEY_WITH_VERSION_SIZE = 78
|
171
177
|
|
172
|
-
HARDENED_THRESHOLD =
|
173
|
-
end
|
178
|
+
HARDENED_THRESHOLD = 2_147_483_648 # 2**31
|
179
|
+
end
|
data/lib/tapyrus/errors.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module Tapyrus
|
2
2
|
module Errors
|
3
3
|
module Messages
|
4
|
-
|
5
4
|
INVALID_PUBLIC_KEY = 'Invalid public key.'
|
6
5
|
INVALID_BIP32_PRIV_PREFIX = 'Invalid BIP32 private key prefix. prefix must be 0x00.'
|
7
6
|
INVALID_BIP32_FINGERPRINT = 'Invalid parent fingerprint.'
|
@@ -11,7 +10,6 @@ module Tapyrus
|
|
11
10
|
|
12
11
|
INVALID_PRIV_KEY = 'Private key is not in range [1..n-1].'
|
13
12
|
INVALID_CHECKSUM = 'Invalid checksum.'
|
14
|
-
|
15
13
|
end
|
16
14
|
end
|
17
|
-
end
|
15
|
+
end
|
data/lib/tapyrus/ext.rb
CHANGED
data/lib/tapyrus/ext/ecdsa.rb
CHANGED
@@ -12,7 +12,6 @@ class ::ECDSA::Point
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ::ECDSA::Format::PointOctetString
|
15
|
-
|
16
15
|
def self.decode(string, group, allow_hybrid: false)
|
17
16
|
string = string.dup.force_encoding('BINARY')
|
18
17
|
|
@@ -29,11 +28,12 @@ module ::ECDSA::Format::PointOctetString
|
|
29
28
|
when 4
|
30
29
|
decode_uncompressed string, group
|
31
30
|
when 6..7
|
32
|
-
|
31
|
+
unless allow_hybrid
|
32
|
+
raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord
|
33
|
+
end
|
33
34
|
decode_uncompressed string, group if allow_hybrid
|
34
35
|
else
|
35
36
|
raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord
|
36
37
|
end
|
37
38
|
end
|
38
|
-
|
39
|
-
end
|
39
|
+
end
|
@@ -2,11 +2,9 @@ require 'json/pure'
|
|
2
2
|
|
3
3
|
module Tapyrus
|
4
4
|
module Ext
|
5
|
-
|
6
5
|
# Extension of JSON::Pure::Parser.
|
7
6
|
# This class convert Float value to String value.
|
8
7
|
class JsonParser < JSON::Pure::Parser
|
9
|
-
|
10
8
|
def parse_value
|
11
9
|
case
|
12
10
|
when scan(FLOAT)
|
@@ -41,7 +39,6 @@ module Tapyrus
|
|
41
39
|
UNPARSED
|
42
40
|
end
|
43
41
|
end
|
44
|
-
|
45
42
|
end
|
46
43
|
end
|
47
|
-
end
|
44
|
+
end
|
data/lib/tapyrus/ext_key.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Tapyrus
|
2
|
-
|
3
2
|
# Integers modulo the order of the curve(secp256k1)
|
4
3
|
CURVE_ORDER = ECDSA::Group::Secp256k1.order
|
5
4
|
|
@@ -45,8 +44,8 @@ module Tapyrus
|
|
45
44
|
|
46
45
|
# serialize extended private key
|
47
46
|
def to_payload
|
48
|
-
version.htb << [depth].pack('C') << parent_fingerprint.htb <<
|
49
|
-
|
47
|
+
version.htb << [depth].pack('C') << parent_fingerprint.htb << [number].pack('N') << chain_code <<
|
48
|
+
[0x00].pack('C') << key.priv_key.htb
|
50
49
|
end
|
51
50
|
|
52
51
|
# Base58 encoded extended private key
|
@@ -108,8 +107,7 @@ module Tapyrus
|
|
108
107
|
raise 'invalid key' if left >= CURVE_ORDER
|
109
108
|
child_priv = (left + key.priv_key.to_i(16)) % CURVE_ORDER
|
110
109
|
raise 'invalid key ' if child_priv >= CURVE_ORDER
|
111
|
-
new_key.key = Tapyrus::Key.new(
|
112
|
-
priv_key: child_priv.to_even_length_hex.rjust(64, '0'), key_type: key_type)
|
110
|
+
new_key.key = Tapyrus::Key.new(priv_key: child_priv.to_even_length_hex.rjust(64, '0'), key_type: key_type)
|
113
111
|
new_key.chain_code = l[32..-1]
|
114
112
|
new_key.ver = version
|
115
113
|
new_key
|
@@ -147,10 +145,14 @@ module Tapyrus
|
|
147
145
|
ext_key.parent_fingerprint = buf.read(4).bth
|
148
146
|
ext_key.number = buf.read(4).unpack('N').first
|
149
147
|
if ext_key.depth == 0
|
150
|
-
|
148
|
+
unless ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
149
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT
|
150
|
+
end
|
151
151
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_key.number > 0
|
152
152
|
end
|
153
|
-
|
153
|
+
if ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_key.depth > 0
|
154
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH
|
155
|
+
end
|
154
156
|
ext_key.chain_code = buf.read(32)
|
155
157
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_PRIV_PREFIX unless buf.read(1).bth == '00' # 0x00
|
156
158
|
ext_key.key = Tapyrus::Key.new(priv_key: buf.read(32).bth, key_type: Tapyrus::Key::TYPES[:compressed])
|
@@ -166,33 +168,34 @@ module Tapyrus
|
|
166
168
|
def self.version_from_purpose(purpose)
|
167
169
|
v = purpose - Tapyrus::HARDENED_THRESHOLD
|
168
170
|
case v
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
171
|
+
when 49
|
172
|
+
Tapyrus.chain_params.bip49_privkey_p2wpkh_p2sh_version
|
173
|
+
when 84
|
174
|
+
Tapyrus.chain_params.bip84_privkey_p2wpkh_version
|
175
|
+
else
|
176
|
+
Tapyrus.chain_params.extended_privkey_version
|
175
177
|
end
|
176
178
|
end
|
177
179
|
|
178
180
|
# check whether +version+ is supported version bytes.
|
179
181
|
def self.support_version?(version)
|
180
182
|
p = Tapyrus.chain_params
|
181
|
-
[p.bip49_privkey_p2wpkh_p2sh_version, p.bip84_privkey_p2wpkh_version, p.extended_privkey_version].include?(
|
183
|
+
[p.bip49_privkey_p2wpkh_p2sh_version, p.bip84_privkey_p2wpkh_version, p.extended_privkey_version].include?(
|
184
|
+
version
|
185
|
+
)
|
182
186
|
end
|
183
187
|
|
184
188
|
# convert privkey version to pubkey version
|
185
189
|
def priv_ver_to_pub_ver
|
186
190
|
case version
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
191
|
+
when Tapyrus.chain_params.bip49_privkey_p2wpkh_p2sh_version
|
192
|
+
Tapyrus.chain_params.bip49_pubkey_p2wpkh_p2sh_version
|
193
|
+
when Tapyrus.chain_params.bip84_privkey_p2wpkh_version
|
194
|
+
Tapyrus.chain_params.bip84_pubkey_p2wpkh_version
|
195
|
+
else
|
196
|
+
Tapyrus.chain_params.extended_pubkey_version
|
193
197
|
end
|
194
198
|
end
|
195
|
-
|
196
199
|
end
|
197
200
|
|
198
201
|
# BIP-32 Extended public key
|
@@ -208,8 +211,7 @@ module Tapyrus
|
|
208
211
|
|
209
212
|
# serialize extended pubkey
|
210
213
|
def to_payload
|
211
|
-
version.htb << [depth].pack('C') <<
|
212
|
-
parent_fingerprint.htb << [number].pack('N') << chain_code << pub.htb
|
214
|
+
version.htb << [depth].pack('C') << parent_fingerprint.htb << [number].pack('N') << chain_code << pub.htb
|
213
215
|
end
|
214
216
|
|
215
217
|
def pub
|
@@ -269,7 +271,7 @@ module Tapyrus
|
|
269
271
|
l = Tapyrus.hmac_sha512(chain_code, data)
|
270
272
|
left = l[0..31].bth.to_i(16)
|
271
273
|
raise 'invalid key' if left >= CURVE_ORDER
|
272
|
-
p1 = Tapyrus::
|
274
|
+
p1 = Tapyrus::Key.new(priv_key: left.to_s(16), key_type: Tapyrus::Key::TYPES[:uncompressed]).to_point
|
273
275
|
p2 = Tapyrus::Key.new(pubkey: pubkey, key_type: key_type).to_point
|
274
276
|
new_key.pubkey = (p1 + p2).to_hex
|
275
277
|
new_key.chain_code = l[32..-1]
|
@@ -309,10 +311,14 @@ module Tapyrus
|
|
309
311
|
ext_pubkey.parent_fingerprint = buf.read(4).bth
|
310
312
|
ext_pubkey.number = buf.read(4).unpack('N').first
|
311
313
|
if ext_pubkey.depth == 0
|
312
|
-
|
314
|
+
unless ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
315
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT
|
316
|
+
end
|
313
317
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_pubkey.number > 0
|
314
318
|
end
|
315
|
-
|
319
|
+
if ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_pubkey.depth > 0
|
320
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH
|
321
|
+
end
|
316
322
|
ext_pubkey.chain_code = buf.read(32)
|
317
323
|
ext_pubkey.pubkey = Tapyrus::Key.new(pubkey: buf.read(33).bth).pubkey
|
318
324
|
ext_pubkey
|
@@ -336,12 +342,12 @@ module Tapyrus
|
|
336
342
|
def self.version_from_purpose(purpose)
|
337
343
|
v = purpose - Tapyrus::HARDENED_THRESHOLD
|
338
344
|
case v
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
+
when 49
|
346
|
+
Tapyrus.chain_params.bip49_pubkey_p2wpkh_p2sh_version
|
347
|
+
when 84
|
348
|
+
Tapyrus.chain_params.bip84_pubkey_p2wpkh_version
|
349
|
+
else
|
350
|
+
Tapyrus.chain_params.extended_pubkey_version
|
345
351
|
end
|
346
352
|
end
|
347
353
|
|
@@ -350,7 +356,5 @@ module Tapyrus
|
|
350
356
|
p = Tapyrus.chain_params
|
351
357
|
[p.bip49_pubkey_p2wpkh_p2sh_version, p.bip84_pubkey_p2wpkh_version, p.extended_pubkey_version].include?(version)
|
352
358
|
end
|
353
|
-
|
354
359
|
end
|
355
|
-
|
356
360
|
end
|
data/lib/tapyrus/key.rb
CHANGED
@@ -2,10 +2,8 @@
|
|
2
2
|
# https://github.com/lian/bitcoin-ruby/blob/master/COPYING
|
3
3
|
|
4
4
|
module Tapyrus
|
5
|
-
|
6
5
|
# tapyrus key class
|
7
6
|
class Key
|
8
|
-
|
9
7
|
PUBLIC_KEY_SIZE = 65
|
10
8
|
COMPRESSED_PUBLIC_KEY_SIZE = 33
|
11
9
|
SIGNATURE_SIZE = 72
|
@@ -18,9 +16,10 @@ module Tapyrus
|
|
18
16
|
attr_accessor :key_type
|
19
17
|
attr_reader :secp256k1_module
|
20
18
|
|
21
|
-
TYPES = {uncompressed: 0x00, compressed: 0x01, p2pkh: 0x10, p2wpkh: 0x11, p2wpkh_p2sh: 0x12}
|
19
|
+
TYPES = { uncompressed: 0x00, compressed: 0x01, p2pkh: 0x10, p2wpkh: 0x11, p2wpkh_p2sh: 0x12 }
|
22
20
|
|
23
21
|
MIN_PRIV_KEY_MOD_ORDER = 0x01
|
22
|
+
|
24
23
|
# Order of secp256k1's generator minus 1.
|
25
24
|
MAX_PRIV_KEY_MOD_ORDER = ECDSA::Group::Secp256k1.order - 1
|
26
25
|
|
@@ -31,18 +30,18 @@ module Tapyrus
|
|
31
30
|
# @param [Boolean] compressed [Deprecated] whether public key is compressed.
|
32
31
|
# @return [Tapyrus::Key] a key object.
|
33
32
|
def initialize(priv_key: nil, pubkey: nil, key_type: nil, compressed: true, allow_hybrid: false)
|
34
|
-
|
33
|
+
if key_type.nil? && !compressed.nil? && pubkey.nil?
|
34
|
+
puts '[Warning] Use key_type parameter instead of compressed. compressed parameter removed in the future.'
|
35
|
+
end
|
35
36
|
if key_type
|
36
37
|
@key_type = key_type
|
37
38
|
compressed = @key_type != TYPES[:uncompressed]
|
38
39
|
else
|
39
40
|
@key_type = compressed ? TYPES[:compressed] : TYPES[:uncompressed]
|
40
41
|
end
|
41
|
-
@secp256k1_module =
|
42
|
+
@secp256k1_module = Tapyrus.secp_impl
|
42
43
|
@priv_key = priv_key
|
43
|
-
if @priv_key
|
44
|
-
raise ArgumentError, Errors::Messages::INVALID_PRIV_KEY unless validate_private_key_range(@priv_key)
|
45
|
-
end
|
44
|
+
raise ArgumentError, Errors::Messages::INVALID_PRIV_KEY unless validate_private_key_range(@priv_key) if @priv_key
|
46
45
|
if pubkey
|
47
46
|
@pubkey = pubkey
|
48
47
|
else
|
@@ -66,7 +65,9 @@ module Tapyrus
|
|
66
65
|
data = hex[2...-8].htb
|
67
66
|
checksum = hex[-8..-1]
|
68
67
|
raise ArgumentError, 'invalid version' unless version == Tapyrus.chain_params.privkey_version
|
69
|
-
|
68
|
+
unless Tapyrus.calc_checksum(version + data.bth) == checksum
|
69
|
+
raise ArgumentError, Errors::Messages::INVALID_CHECKSUM
|
70
|
+
end
|
70
71
|
key_len = data.bytesize
|
71
72
|
if key_len == COMPRESSED_PUBLIC_KEY_SIZE && data[-1].unpack('C').first == 1
|
72
73
|
key_type = TYPES[:compressed]
|
@@ -95,7 +96,7 @@ module Tapyrus
|
|
95
96
|
# @param [Symbol] algo Algorithms used for verification. Either :ecdsa or :schnorr is supported. default value is :ecdsa.
|
96
97
|
# @return [String] signature data with binary format
|
97
98
|
def sign(data, low_r = true, extra_entropy = nil, algo: :ecdsa)
|
98
|
-
raise ArgumentError,
|
99
|
+
raise ArgumentError, 'Unsupported algorithm has been specified.' unless SIG_ALGO.include?(algo)
|
99
100
|
case algo
|
100
101
|
when :ecdsa
|
101
102
|
sign_ecdsa(data, low_r, extra_entropy)
|
@@ -114,7 +115,7 @@ module Tapyrus
|
|
114
115
|
def verify(sig, origin, algo: :ecdsa)
|
115
116
|
return false unless valid_pubkey?
|
116
117
|
begin
|
117
|
-
raise ArgumentError,
|
118
|
+
raise ArgumentError, 'Unsupported algorithm has been specified.' unless SIG_ALGO.include?(algo)
|
118
119
|
sig = ecdsa_signature_parse_der_lax(sig) if algo == :ecdsa
|
119
120
|
secp256k1_module.verify_sig(origin, sig, pubkey, algo: algo)
|
120
121
|
rescue Exception
|
@@ -150,12 +151,12 @@ module Tapyrus
|
|
150
151
|
p = pubkey.htb
|
151
152
|
return false if p.bytesize < COMPRESSED_PUBLIC_KEY_SIZE
|
152
153
|
case p[0]
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
154
|
+
when "\x04"
|
155
|
+
return false unless p.bytesize == PUBLIC_KEY_SIZE
|
156
|
+
when "\x02", "\x03"
|
157
|
+
return false unless p.bytesize == COMPRESSED_PUBLIC_KEY_SIZE
|
158
|
+
else
|
159
|
+
return false
|
159
160
|
end
|
160
161
|
true
|
161
162
|
end
|
@@ -172,16 +173,17 @@ module Tapyrus
|
|
172
173
|
len_r = s[3]
|
173
174
|
len_s = s[5 + len_r]
|
174
175
|
val_s = s.slice(6 + len_r, len_s)
|
176
|
+
|
177
|
+
# prettier-ignore
|
175
178
|
max_mod_half_order = [
|
176
|
-
0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
177
|
-
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
178
|
-
0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,
|
179
|
-
0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0
|
180
|
-
|
181
|
-
|
179
|
+
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
180
|
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
181
|
+
0x5d, 0x57, 0x6e, 0x73, 0x57, 0xa4, 0x50, 0x1d,
|
182
|
+
0xdf, 0xe9, 0x2f, 0x46, 0x68, 0x1b, 0x20, 0xa0
|
183
|
+
]
|
184
|
+
compare_big_endian(val_s, [0]) > 0 && compare_big_endian(val_s, max_mod_half_order) <= 0
|
182
185
|
end
|
183
186
|
|
184
|
-
|
185
187
|
# check +sig+ is correct der encoding.
|
186
188
|
# This function is consensus-critical since BIP66.
|
187
189
|
# @param [String] sig a signature data with binary format.
|
@@ -233,15 +235,11 @@ module Tapyrus
|
|
233
235
|
def self.compare_big_endian(c1, c2)
|
234
236
|
c1, c2 = c1.dup, c2.dup # Clone the arrays
|
235
237
|
|
236
|
-
while c1.size > c2.size
|
237
|
-
return 1 if c1.shift > 0
|
238
|
-
end
|
238
|
+
return 1 if c1.shift > 0 while c1.size > c2.size
|
239
239
|
|
240
|
-
while c2.size > c1.size
|
241
|
-
return -1 if c2.shift > 0
|
242
|
-
end
|
240
|
+
return -1 if c2.shift > 0 while c2.size > c1.size
|
243
241
|
|
244
|
-
c1.size.times{|idx| return c1[idx] - c2[idx] if c1[idx] != c2[idx] }
|
242
|
+
c1.size.times { |idx| return c1[idx] - c2[idx] if c1[idx] != c2[idx] }
|
245
243
|
0
|
246
244
|
end
|
247
245
|
|
@@ -267,7 +265,7 @@ module Tapyrus
|
|
267
265
|
def ecdsa_signature_parse_der_lax(sig)
|
268
266
|
sig_array = sig.unpack('C*')
|
269
267
|
len_r = sig_array[3]
|
270
|
-
r = sig_array[4...(len_r+4)].pack('C*').bth
|
268
|
+
r = sig_array[4...(len_r + 4)].pack('C*').bth
|
271
269
|
len_s = sig_array[len_r + 5]
|
272
270
|
s = sig_array[(len_r + 6)...(len_r + 6 + len_s)].pack('C*').bth
|
273
271
|
ECDSA::Signature.new(r.to_i(16), s.to_i(16)).to_der
|
@@ -291,13 +289,11 @@ module Tapyrus
|
|
291
289
|
counter = 1
|
292
290
|
until sig_has_low_r?(sig)
|
293
291
|
extra_entropy = [counter].pack('I*').bth.ljust(64, '0').htb
|
294
|
-
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy,
|
292
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :ecdsa)
|
295
293
|
counter += 1
|
296
294
|
end
|
297
295
|
end
|
298
296
|
sig
|
299
297
|
end
|
300
|
-
|
301
298
|
end
|
302
|
-
|
303
299
|
end
|