tapyrus 0.2.7 → 0.2.12

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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +37 -0
  3. data/.prettierignore +3 -0
  4. data/.prettierrc.yaml +3 -0
  5. data/.ruby-version +1 -1
  6. data/CODE_OF_CONDUCT.md +7 -7
  7. data/README.md +14 -17
  8. data/Rakefile +3 -3
  9. data/lib/openassets/marker_output.rb +0 -4
  10. data/lib/openassets/payload.rb +4 -10
  11. data/lib/openassets.rb +0 -2
  12. data/lib/schnorr/sign_to_contract.rb +51 -0
  13. data/lib/schnorr/signature.rb +3 -6
  14. data/lib/schnorr.rb +14 -9
  15. data/lib/tapyrus/base58.rb +7 -6
  16. data/lib/tapyrus/bip175.rb +78 -0
  17. data/lib/tapyrus/block.rb +1 -2
  18. data/lib/tapyrus/block_header.rb +15 -9
  19. data/lib/tapyrus/bloom_filter.rb +5 -3
  20. data/lib/tapyrus/chain_params.rb +1 -4
  21. data/lib/tapyrus/chainparams/dev.yml +3 -2
  22. data/lib/tapyrus/chainparams/prod.yml +3 -2
  23. data/lib/tapyrus/constants.rb +29 -23
  24. data/lib/tapyrus/errors.rb +1 -3
  25. data/lib/tapyrus/ext/ecdsa.rb +4 -4
  26. data/lib/tapyrus/ext/json_parser.rb +1 -4
  27. data/lib/tapyrus/ext.rb +1 -1
  28. data/lib/tapyrus/ext_key.rb +44 -32
  29. data/lib/tapyrus/key.rb +31 -35
  30. data/lib/tapyrus/key_path.rb +15 -12
  31. data/lib/tapyrus/logger.rb +20 -16
  32. data/lib/tapyrus/merkle_tree.rb +22 -20
  33. data/lib/tapyrus/message/addr.rb +1 -7
  34. data/lib/tapyrus/message/base.rb +0 -3
  35. data/lib/tapyrus/message/block.rb +2 -9
  36. data/lib/tapyrus/message/block_transaction_request.rb +3 -6
  37. data/lib/tapyrus/message/block_transactions.rb +2 -6
  38. data/lib/tapyrus/message/block_txn.rb +0 -4
  39. data/lib/tapyrus/message/cmpct_block.rb +1 -7
  40. data/lib/tapyrus/message/error.rb +1 -4
  41. data/lib/tapyrus/message/fee_filter.rb +1 -4
  42. data/lib/tapyrus/message/filter_add.rb +0 -4
  43. data/lib/tapyrus/message/filter_clear.rb +0 -4
  44. data/lib/tapyrus/message/filter_load.rb +2 -5
  45. data/lib/tapyrus/message/get_addr.rb +0 -4
  46. data/lib/tapyrus/message/get_block_txn.rb +0 -4
  47. data/lib/tapyrus/message/get_blocks.rb +0 -3
  48. data/lib/tapyrus/message/get_data.rb +1 -4
  49. data/lib/tapyrus/message/get_headers.rb +1 -3
  50. data/lib/tapyrus/message/header_and_short_ids.rb +3 -9
  51. data/lib/tapyrus/message/headers.rb +0 -4
  52. data/lib/tapyrus/message/headers_parser.rb +3 -8
  53. data/lib/tapyrus/message/inv.rb +1 -4
  54. data/lib/tapyrus/message/inventories_parser.rb +2 -7
  55. data/lib/tapyrus/message/inventory.rb +12 -5
  56. data/lib/tapyrus/message/mem_pool.rb +0 -4
  57. data/lib/tapyrus/message/merkle_block.rb +4 -9
  58. data/lib/tapyrus/message/network_addr.rb +7 -6
  59. data/lib/tapyrus/message/not_found.rb +0 -3
  60. data/lib/tapyrus/message/ping.rb +0 -3
  61. data/lib/tapyrus/message/pong.rb +0 -3
  62. data/lib/tapyrus/message/prefilled_tx.rb +0 -4
  63. data/lib/tapyrus/message/reject.rb +0 -3
  64. data/lib/tapyrus/message/send_cmpct.rb +1 -3
  65. data/lib/tapyrus/message/send_headers.rb +0 -3
  66. data/lib/tapyrus/message/tx.rb +0 -4
  67. data/lib/tapyrus/message/ver_ack.rb +1 -5
  68. data/lib/tapyrus/message/version.rb +2 -5
  69. data/lib/tapyrus/message.rb +14 -16
  70. data/lib/tapyrus/mnemonic.rb +17 -15
  71. data/lib/tapyrus/network/connection.rb +0 -3
  72. data/lib/tapyrus/network/message_handler.rb +61 -60
  73. data/lib/tapyrus/network/peer.rb +13 -12
  74. data/lib/tapyrus/network/peer_discovery.rb +10 -9
  75. data/lib/tapyrus/network/pool.rb +12 -12
  76. data/lib/tapyrus/network.rb +0 -2
  77. data/lib/tapyrus/node/cli.rb +12 -14
  78. data/lib/tapyrus/node/configuration.rb +1 -3
  79. data/lib/tapyrus/node/spv.rb +2 -3
  80. data/lib/tapyrus/node.rb +1 -1
  81. data/lib/tapyrus/opcodes.rb +9 -7
  82. data/lib/tapyrus/out_point.rb +5 -5
  83. data/lib/tapyrus/rpc/http_server.rb +21 -22
  84. data/lib/tapyrus/rpc/request_handler.rb +16 -21
  85. data/lib/tapyrus/rpc/tapyrus_core_client.rb +67 -25
  86. data/lib/tapyrus/rpc.rb +1 -0
  87. data/lib/tapyrus/script/color.rb +10 -0
  88. data/lib/tapyrus/script/multisig.rb +13 -12
  89. data/lib/tapyrus/script/script.rb +93 -88
  90. data/lib/tapyrus/script/script_error.rb +1 -4
  91. data/lib/tapyrus/script/script_interpreter.rb +439 -399
  92. data/lib/tapyrus/script/tx_checker.rb +20 -10
  93. data/lib/tapyrus/secp256k1/native.rb +14 -15
  94. data/lib/tapyrus/secp256k1/rfc6979.rb +7 -4
  95. data/lib/tapyrus/secp256k1/ruby.rb +10 -12
  96. data/lib/tapyrus/secp256k1.rb +0 -4
  97. data/lib/tapyrus/slip39/share.rb +41 -29
  98. data/lib/tapyrus/slip39/sss.rb +92 -49
  99. data/lib/tapyrus/slip39.rb +20 -5
  100. data/lib/tapyrus/store/chain_entry.rb +0 -4
  101. data/lib/tapyrus/store/db/level_db.rb +5 -9
  102. data/lib/tapyrus/store/db.rb +0 -2
  103. data/lib/tapyrus/store/spv_chain.rb +11 -17
  104. data/lib/tapyrus/store.rb +1 -3
  105. data/lib/tapyrus/tx.rb +45 -37
  106. data/lib/tapyrus/tx_builder.rb +160 -0
  107. data/lib/tapyrus/tx_in.rb +1 -6
  108. data/lib/tapyrus/tx_out.rb +2 -7
  109. data/lib/tapyrus/util.rb +7 -9
  110. data/lib/tapyrus/validation.rb +12 -11
  111. data/lib/tapyrus/version.rb +1 -1
  112. data/lib/tapyrus/wallet/account.rb +22 -18
  113. data/lib/tapyrus/wallet/base.rb +12 -9
  114. data/lib/tapyrus/wallet/db.rb +6 -9
  115. data/lib/tapyrus/wallet/master_key.rb +2 -4
  116. data/lib/tapyrus.rb +7 -22
  117. data/tapyrusrb.gemspec +13 -14
  118. metadata +26 -7
  119. data/.travis.yml +0 -14
@@ -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 = 0
30
- SCRIPT_VERIFY_P2SH = (1 << 0)
32
+ SCRIPT_VERIFY_NONE = 0
33
+ SCRIPT_VERIFY_P2SH = (1 << 0)
31
34
  SCRIPT_VERIFY_STRICTENC = (1 << 1)
32
- SCRIPT_VERIFY_DERSIG = (1 << 2)
33
- SCRIPT_VERIFY_LOW_S = (1 << 3)
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 = [MANDATORY_SCRIPT_VERIFY_FLAGS,
49
- SCRIPT_VERIFY_DERSIG,
50
- SCRIPT_VERIFY_STRICTENC,
51
- SCRIPT_VERIFY_MINIMALDATA,
52
- SCRIPT_VERIFY_NULLDUMMY,
53
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
54
- SCRIPT_VERIFY_CLEANSTACK,
55
- SCRIPT_VERIFY_MINIMALIF,
56
- SCRIPT_VERIFY_NULLFAIL,
57
- SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
58
- SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
59
- SCRIPT_VERIFY_LOW_S,
60
- SCRIPT_VERIFY_CONST_SCRIPTCODE].inject(SCRIPT_VERIFY_NONE){|flags, f| flags |= f}
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 = 10000
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 = 500000000
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 = 2147483648 # 2**31
173
- end
178
+ HARDENED_THRESHOLD = 2_147_483_648 # 2**31
179
+ end
@@ -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
@@ -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
- raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord unless allow_hybrid
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.rb CHANGED
@@ -2,4 +2,4 @@ module Tapyrus
2
2
  module Ext
3
3
  autoload :JsonParser, 'tapyrus/ext/json_parser'
4
4
  end
5
- end
5
+ end
@@ -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
- [number].pack('N') << chain_code << [0x00].pack('C') << key.priv_key.htb
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
- raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT unless ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
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
- raise ArgumentError, Errors::Messages:: INVALID_BIP32_ZERO_DEPTH if ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_key.depth > 0
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,38 @@ module Tapyrus
166
168
  def self.version_from_purpose(purpose)
167
169
  v = purpose - Tapyrus::HARDENED_THRESHOLD
168
170
  case v
169
- when 49
170
- Tapyrus.chain_params.bip49_privkey_p2wpkh_p2sh_version
171
- when 84
172
- Tapyrus.chain_params.bip84_privkey_p2wpkh_version
173
- else
174
- Tapyrus.chain_params.extended_privkey_version
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?(version)
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
- when Tapyrus.chain_params.bip49_privkey_p2wpkh_p2sh_version
188
- Tapyrus.chain_params.bip49_pubkey_p2wpkh_p2sh_version
189
- when Tapyrus.chain_params.bip84_privkey_p2wpkh_version
190
- Tapyrus.chain_params.bip84_pubkey_p2wpkh_version
191
- else
192
- Tapyrus.chain_params.extended_pubkey_version
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
199
 
200
+ def master?
201
+ depth == 0 && number == 0 && parent_fingerprint == '00000000'
202
+ end
196
203
  end
197
204
 
198
205
  # BIP-32 Extended public key
@@ -208,8 +215,7 @@ module Tapyrus
208
215
 
209
216
  # serialize extended pubkey
210
217
  def to_payload
211
- version.htb << [depth].pack('C') <<
212
- parent_fingerprint.htb << [number].pack('N') << chain_code << pub.htb
218
+ version.htb << [depth].pack('C') << parent_fingerprint.htb << [number].pack('N') << chain_code << pub.htb
213
219
  end
214
220
 
215
221
  def pub
@@ -269,7 +275,7 @@ module Tapyrus
269
275
  l = Tapyrus.hmac_sha512(chain_code, data)
270
276
  left = l[0..31].bth.to_i(16)
271
277
  raise 'invalid key' if left >= CURVE_ORDER
272
- p1 = Tapyrus::Secp256k1::GROUP.generator.multiply_by_scalar(left)
278
+ p1 = Tapyrus::Key.new(priv_key: left.to_s(16), key_type: Tapyrus::Key::TYPES[:uncompressed]).to_point
273
279
  p2 = Tapyrus::Key.new(pubkey: pubkey, key_type: key_type).to_point
274
280
  new_key.pubkey = (p1 + p2).to_hex
275
281
  new_key.chain_code = l[32..-1]
@@ -309,10 +315,14 @@ module Tapyrus
309
315
  ext_pubkey.parent_fingerprint = buf.read(4).bth
310
316
  ext_pubkey.number = buf.read(4).unpack('N').first
311
317
  if ext_pubkey.depth == 0
312
- raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT unless ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
318
+ unless ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
319
+ raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT
320
+ end
313
321
  raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_INDEX if ext_pubkey.number > 0
314
322
  end
315
- raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH if ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_pubkey.depth > 0
323
+ if ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT && ext_pubkey.depth > 0
324
+ raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH
325
+ end
316
326
  ext_pubkey.chain_code = buf.read(32)
317
327
  ext_pubkey.pubkey = Tapyrus::Key.new(pubkey: buf.read(33).bth).pubkey
318
328
  ext_pubkey
@@ -336,12 +346,12 @@ module Tapyrus
336
346
  def self.version_from_purpose(purpose)
337
347
  v = purpose - Tapyrus::HARDENED_THRESHOLD
338
348
  case v
339
- when 49
340
- Tapyrus.chain_params.bip49_pubkey_p2wpkh_p2sh_version
341
- when 84
342
- Tapyrus.chain_params.bip84_pubkey_p2wpkh_version
343
- else
344
- Tapyrus.chain_params.extended_pubkey_version
349
+ when 49
350
+ Tapyrus.chain_params.bip49_pubkey_p2wpkh_p2sh_version
351
+ when 84
352
+ Tapyrus.chain_params.bip84_pubkey_p2wpkh_version
353
+ else
354
+ Tapyrus.chain_params.extended_pubkey_version
345
355
  end
346
356
  end
347
357
 
@@ -351,6 +361,8 @@ module Tapyrus
351
361
  [p.bip49_pubkey_p2wpkh_p2sh_version, p.bip84_pubkey_p2wpkh_version, p.extended_pubkey_version].include?(version)
352
362
  end
353
363
 
364
+ def master?
365
+ depth == 0 && number == 0 && parent_fingerprint == '00000000'
366
+ end
354
367
  end
355
-
356
368
  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
- puts "[Warning] Use key_type parameter instead of compressed. compressed parameter removed in the future." if key_type.nil? && !compressed.nil? && pubkey.nil?
33
+ if key_type.nil? && !compressed.nil? && pubkey.nil?
34
+ warn('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 = Tapyrus.secp_impl
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
- raise ArgumentError, Errors::Messages::INVALID_CHECKSUM unless Tapyrus.calc_checksum(version + data.bth) == checksum
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, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
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, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
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
- when "\x04"
154
- return false unless p.bytesize == PUBLIC_KEY_SIZE
155
- when "\x02", "\x03"
156
- return false unless p.bytesize == COMPRESSED_PUBLIC_KEY_SIZE
157
- else
158
- return false
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
- compare_big_endian(val_s, [0]) > 0 &&
181
- compare_big_endian(val_s, max_mod_half_order) <= 0
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, algo: :ecdsa)
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
@@ -1,26 +1,29 @@
1
1
  module Tapyrus
2
2
  module KeyPath
3
-
4
3
  # key path convert an array of derive number
5
4
  # @param [String] path_string
6
5
  # @return [Array[Integer]] key path numbers.
7
6
  def parse_key_path(path_string)
8
- path_string.split('/').map.with_index do|p, index|
9
- if index == 0
10
- raise ArgumentError.new("#{path_string} is invalid format.") unless p == 'm'
11
- next
12
- end
13
- raise ArgumentError.new("#{path_string} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
14
- (p[-1] == "'" ? p.delete("'").to_i + Tapyrus::HARDENED_THRESHOLD : p.to_i)
15
- end[1..-1]
7
+ path_string
8
+ .split('/')
9
+ .map
10
+ .with_index do |p, index|
11
+ if index == 0
12
+ raise ArgumentError.new("#{path_string} is invalid format.") unless p == 'm'
13
+ next
14
+ end
15
+ raise ArgumentError.new("#{path_string} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
16
+ (p[-1] == "'" ? p.delete("'").to_i + Tapyrus::HARDENED_THRESHOLD : p.to_i)
17
+ end[
18
+ 1..-1
19
+ ]
16
20
  end
17
21
 
18
22
  # key path numbers convert to path string.
19
23
  # @param [Array[Integer]] key path numbers.
20
24
  # @return [String] path string.
21
25
  def to_key_path(numbers)
22
- "m/#{numbers.map{|p| p >= Tapyrus::HARDENED_THRESHOLD ? "#{p - Tapyrus::HARDENED_THRESHOLD}'" : p.to_s}.join('/')}"
26
+ "m/#{numbers.map { |p| p >= Tapyrus::HARDENED_THRESHOLD ? "#{p - Tapyrus::HARDENED_THRESHOLD}'" : p.to_s }.join('/')}"
23
27
  end
24
-
25
28
  end
26
- end
29
+ end
@@ -1,10 +1,8 @@
1
1
  require 'logger'
2
2
 
3
3
  module Tapyrus
4
-
5
4
  # Simple Logger module
6
5
  module Logger
7
-
8
6
  Format = "%s, [%s#%d #%d] %5s -- %s: %s\n".freeze
9
7
 
10
8
  module_function
@@ -15,28 +13,34 @@ module Tapyrus
15
13
  FileUtils.mkdir_p(dir)
16
14
  logger = ::Logger.new(dir + "/#{name}.log", 10)
17
15
  logger.level = level
18
- logger.formatter = proc do |severity, datetime, progname, msg|
19
- Format % [severity[0..0], format_datetime(datetime), $$,
20
- Thread.current.object_id, severity, progname, msg2str(msg)]
21
- end
16
+ logger.formatter =
17
+ proc do |severity, datetime, progname, msg|
18
+ Format % [
19
+ severity[0..0],
20
+ format_datetime(datetime),
21
+ $$,
22
+ Thread.current.object_id,
23
+ severity,
24
+ progname,
25
+ msg2str(msg)
26
+ ]
27
+ end
22
28
  logger
23
29
  end
24
30
 
25
31
  def self.msg2str(msg)
26
32
  case msg
27
- when ::String
28
- msg
29
- when ::Exception
30
- "#{ msg.message } (#{ msg.class })\n" <<
31
- (msg.backtrace || []).join("\n")
32
- else
33
- msg.inspect
33
+ when ::String
34
+ msg
35
+ when ::Exception
36
+ "#{msg.message} (#{msg.class})\n" << (msg.backtrace || []).join("\n")
37
+ else
38
+ msg.inspect
34
39
  end
35
40
  end
36
41
 
37
42
  def format_datetime(time)
38
- time.strftime(@datetime_format || "%Y-%m-%dT%H:%M:%S.%6N ".freeze)
43
+ time.strftime(@datetime_format || '%Y-%m-%dT%H:%M:%S.%6N '.freeze)
39
44
  end
40
-
41
45
  end
42
- end
46
+ end