tapyrus 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/{.prettierrc.yaml → .prettierrc.yml} +0 -1
- data/.ruby-version +1 -1
- data/Gemfile +2 -2
- data/README.md +1 -1
- data/Rakefile +2 -2
- data/exe/tapyrus-script-debugger +5 -5
- data/exe/tapyrusrb-cli +1 -1
- data/exe/tapyrusrbd +18 -17
- data/lib/openassets/payload.rb +2 -2
- data/lib/openassets/util.rb +2 -2
- data/lib/openassets.rb +4 -4
- data/lib/schnorr/sign_to_contract.rb +4 -4
- data/lib/schnorr/signature.rb +5 -5
- data/lib/schnorr.rb +14 -14
- data/lib/tapyrus/base58.rb +8 -8
- data/lib/tapyrus/bip175.rb +5 -5
- data/lib/tapyrus/block_header.rb +2 -2
- data/lib/tapyrus/bloom_filter.rb +1 -1
- data/lib/tapyrus/chain_params.rb +5 -5
- data/lib/tapyrus/constants.rb +1 -1
- data/lib/tapyrus/errors.rb +9 -9
- data/lib/tapyrus/ext/ecdsa.rb +4 -4
- data/lib/tapyrus/ext/json_parser.rb +1 -1
- data/lib/tapyrus/ext.rb +3 -3
- data/lib/tapyrus/ext_key.rb +21 -21
- data/lib/tapyrus/jws.rb +76 -0
- data/lib/tapyrus/key.rb +48 -20
- data/lib/tapyrus/key_path.rb +3 -3
- data/lib/tapyrus/logger.rb +4 -11
- data/lib/tapyrus/merkle_tree.rb +1 -1
- data/lib/tapyrus/message/addr.rb +2 -2
- data/lib/tapyrus/message/base.rb +2 -2
- data/lib/tapyrus/message/block.rb +1 -1
- data/lib/tapyrus/message/block_txn.rb +1 -1
- data/lib/tapyrus/message/cmpct_block.rb +1 -1
- data/lib/tapyrus/message/fee_filter.rb +3 -3
- data/lib/tapyrus/message/filter_add.rb +1 -1
- data/lib/tapyrus/message/filter_clear.rb +2 -2
- data/lib/tapyrus/message/filter_load.rb +7 -7
- data/lib/tapyrus/message/get_addr.rb +2 -2
- data/lib/tapyrus/message/get_block_txn.rb +1 -1
- data/lib/tapyrus/message/get_blocks.rb +1 -1
- data/lib/tapyrus/message/get_data.rb +1 -1
- data/lib/tapyrus/message/get_headers.rb +1 -1
- data/lib/tapyrus/message/header_and_short_ids.rb +6 -6
- data/lib/tapyrus/message/headers.rb +1 -1
- data/lib/tapyrus/message/headers_parser.rb +2 -2
- data/lib/tapyrus/message/inv.rb +1 -1
- data/lib/tapyrus/message/inventory.rb +3 -3
- data/lib/tapyrus/message/mem_pool.rb +2 -2
- data/lib/tapyrus/message/merkle_block.rb +3 -3
- data/lib/tapyrus/message/network_addr.rb +9 -9
- data/lib/tapyrus/message/not_found.rb +1 -1
- data/lib/tapyrus/message/ping.rb +3 -3
- data/lib/tapyrus/message/pong.rb +3 -3
- data/lib/tapyrus/message/reject.rb +6 -6
- data/lib/tapyrus/message/send_cmpct.rb +4 -4
- data/lib/tapyrus/message/send_headers.rb +2 -2
- data/lib/tapyrus/message/tx.rb +1 -1
- data/lib/tapyrus/message/ver_ack.rb +2 -2
- data/lib/tapyrus/message/version.rb +7 -7
- data/lib/tapyrus/message.rb +37 -37
- data/lib/tapyrus/mnemonic.rb +18 -16
- data/lib/tapyrus/network/connection.rb +2 -2
- data/lib/tapyrus/network/message_handler.rb +11 -11
- data/lib/tapyrus/network/peer.rb +1 -1
- data/lib/tapyrus/network/peer_discovery.rb +1 -1
- data/lib/tapyrus/network/pool.rb +4 -4
- data/lib/tapyrus/network.rb +6 -6
- data/lib/tapyrus/node/cli.rb +34 -34
- data/lib/tapyrus/node/configuration.rb +3 -3
- data/lib/tapyrus/node/spv.rb +2 -2
- data/lib/tapyrus/node.rb +3 -3
- data/lib/tapyrus/opcodes.rb +7 -7
- data/lib/tapyrus/out_point.rb +2 -2
- data/lib/tapyrus/rpc/http_server.rb +6 -6
- data/lib/tapyrus/rpc/request_handler.rb +5 -5
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +10 -10
- data/lib/tapyrus/rpc.rb +4 -4
- data/lib/tapyrus/script/color.rb +3 -3
- data/lib/tapyrus/script/debugger.rb +9 -9
- data/lib/tapyrus/script/multisig.rb +2 -2
- data/lib/tapyrus/script/script.rb +28 -28
- data/lib/tapyrus/script/script_error.rb +42 -42
- data/lib/tapyrus/script/script_interpreter.rb +9 -9
- data/lib/tapyrus/script/tx_checker.rb +2 -2
- data/lib/tapyrus/secp256k1/native.rb +23 -23
- data/lib/tapyrus/secp256k1/rfc6979.rb +7 -7
- data/lib/tapyrus/secp256k1/ruby.rb +2 -2
- data/lib/tapyrus/secp256k1.rb +3 -3
- data/lib/tapyrus/slip39/share.rb +7 -7
- data/lib/tapyrus/slip39/sss.rb +24 -24
- data/lib/tapyrus/slip39.rb +514 -37
- data/lib/tapyrus/store/db/level_db.rb +2 -2
- data/lib/tapyrus/store/db.rb +1 -1
- data/lib/tapyrus/store/spv_chain.rb +7 -7
- data/lib/tapyrus/store.rb +3 -3
- data/lib/tapyrus/tip0137.rb +201 -0
- data/lib/tapyrus/tx.rb +12 -12
- data/lib/tapyrus/tx_builder.rb +3 -3
- data/lib/tapyrus/tx_in.rb +3 -3
- data/lib/tapyrus/tx_out.rb +3 -3
- data/lib/tapyrus/util.rb +21 -21
- data/lib/tapyrus/validation.rb +9 -9
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +12 -12
- data/lib/tapyrus/wallet/base.rb +9 -8
- data/lib/tapyrus/wallet/db.rb +11 -11
- data/lib/tapyrus/wallet/master_key.rb +13 -13
- data/lib/tapyrus/wallet.rb +4 -4
- data/lib/tapyrus.rb +62 -59
- data/tapyrusrb.gemspec +33 -31
- metadata +30 -14
data/lib/tapyrus/ext_key.rb
CHANGED
@@ -7,7 +7,7 @@ module Tapyrus
|
|
7
7
|
include Tapyrus::HexConverter
|
8
8
|
|
9
9
|
MAX_DEPTH = 255
|
10
|
-
MASTER_FINGERPRINT =
|
10
|
+
MASTER_FINGERPRINT = "00000000"
|
11
11
|
|
12
12
|
attr_accessor :ver
|
13
13
|
attr_accessor :depth
|
@@ -21,10 +21,10 @@ module Tapyrus
|
|
21
21
|
def self.generate_master(seed)
|
22
22
|
ext_key = ExtKey.new
|
23
23
|
ext_key.depth = ext_key.number = 0
|
24
|
-
ext_key.parent_fingerprint =
|
25
|
-
l = Tapyrus.hmac_sha512(
|
24
|
+
ext_key.parent_fingerprint = "00000000"
|
25
|
+
l = Tapyrus.hmac_sha512("Tapyrus seed", seed.htb)
|
26
26
|
left = l[0..31].bth.to_i(16)
|
27
|
-
raise
|
27
|
+
raise "invalid key" if left >= CURVE_ORDER || left == 0
|
28
28
|
l_priv = ECDSA::Format::IntegerOctetString.encode(left, 32)
|
29
29
|
ext_key.key = Tapyrus::Key.new(priv_key: l_priv.bth, key_type: Tapyrus::Key::TYPES[:compressed])
|
30
30
|
ext_key.chain_code = l[32..-1]
|
@@ -45,8 +45,8 @@ module Tapyrus
|
|
45
45
|
|
46
46
|
# serialize extended private key
|
47
47
|
def to_payload
|
48
|
-
version.htb << [depth].pack(
|
49
|
-
[0x00].pack(
|
48
|
+
version.htb << [depth].pack("C") << parent_fingerprint.htb << [number].pack("N") << chain_code <<
|
49
|
+
[0x00].pack("C") << key.priv_key.htb
|
50
50
|
end
|
51
51
|
|
52
52
|
# Base58 encoded extended private key
|
@@ -99,15 +99,15 @@ module Tapyrus
|
|
99
99
|
new_key.number = number
|
100
100
|
new_key.parent_fingerprint = fingerprint
|
101
101
|
if number > (Tapyrus::HARDENED_THRESHOLD - 1)
|
102
|
-
data = [0x00].pack(
|
102
|
+
data = [0x00].pack("C") << key.priv_key.htb << [number].pack("N")
|
103
103
|
else
|
104
|
-
data = key.pubkey.htb << [number].pack(
|
104
|
+
data = key.pubkey.htb << [number].pack("N")
|
105
105
|
end
|
106
106
|
l = Tapyrus.hmac_sha512(chain_code, data)
|
107
107
|
left = l[0..31].bth.to_i(16)
|
108
|
-
raise
|
108
|
+
raise "invalid key" if left >= CURVE_ORDER
|
109
109
|
child_priv = (left + key.priv_key.to_i(16)) % CURVE_ORDER
|
110
|
-
raise
|
110
|
+
raise "invalid key " if child_priv >= CURVE_ORDER
|
111
111
|
child_priv = ECDSA::Format::IntegerOctetString.encode(child_priv, 32)
|
112
112
|
new_key.key = Tapyrus::Key.new(priv_key: child_priv.bth, key_type: key_type)
|
113
113
|
new_key.chain_code = l[32..-1]
|
@@ -143,9 +143,9 @@ module Tapyrus
|
|
143
143
|
ext_key = ExtKey.new
|
144
144
|
ext_key.ver = buf.read(4).bth # version
|
145
145
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_VERSION unless ExtKey.support_version?(ext_key.ver)
|
146
|
-
ext_key.depth = buf.read(1).unpack(
|
146
|
+
ext_key.depth = buf.read(1).unpack("C").first
|
147
147
|
ext_key.parent_fingerprint = buf.read(4).bth
|
148
|
-
ext_key.number = buf.read(4).unpack(
|
148
|
+
ext_key.number = buf.read(4).unpack("N").first
|
149
149
|
if ext_key.depth == 0
|
150
150
|
unless ext_key.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
151
151
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT
|
@@ -156,7 +156,7 @@ module Tapyrus
|
|
156
156
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_ZERO_DEPTH
|
157
157
|
end
|
158
158
|
ext_key.chain_code = buf.read(32)
|
159
|
-
raise ArgumentError, Errors::Messages::INVALID_BIP32_PRIV_PREFIX unless buf.read(1).bth ==
|
159
|
+
raise ArgumentError, Errors::Messages::INVALID_BIP32_PRIV_PREFIX unless buf.read(1).bth == "00" # 0x00
|
160
160
|
ext_key.key = Tapyrus::Key.new(priv_key: buf.read(32).bth, key_type: Tapyrus::Key::TYPES[:compressed])
|
161
161
|
ext_key
|
162
162
|
end
|
@@ -200,7 +200,7 @@ module Tapyrus
|
|
200
200
|
end
|
201
201
|
|
202
202
|
def master?
|
203
|
-
depth == 0 && number == 0 && parent_fingerprint ==
|
203
|
+
depth == 0 && number == 0 && parent_fingerprint == "00000000"
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
@@ -217,7 +217,7 @@ module Tapyrus
|
|
217
217
|
|
218
218
|
# serialize extended pubkey
|
219
219
|
def to_payload
|
220
|
-
version.htb << [depth].pack(
|
220
|
+
version.htb << [depth].pack("C") << parent_fingerprint.htb << [number].pack("N") << chain_code << pub.htb
|
221
221
|
end
|
222
222
|
|
223
223
|
def pub
|
@@ -272,11 +272,11 @@ module Tapyrus
|
|
272
272
|
new_key.depth = depth + 1
|
273
273
|
new_key.number = number
|
274
274
|
new_key.parent_fingerprint = fingerprint
|
275
|
-
raise
|
276
|
-
data = pub.htb << [number].pack(
|
275
|
+
raise "hardened key is not support" if number > (Tapyrus::HARDENED_THRESHOLD - 1)
|
276
|
+
data = pub.htb << [number].pack("N")
|
277
277
|
l = Tapyrus.hmac_sha512(chain_code, data)
|
278
278
|
left = l[0..31].bth.to_i(16)
|
279
|
-
raise
|
279
|
+
raise "invalid key" if left >= CURVE_ORDER
|
280
280
|
l_priv = ECDSA::Format::IntegerOctetString.encode(left, 32)
|
281
281
|
p1 = Tapyrus::Key.new(priv_key: l_priv.bth, key_type: Tapyrus::Key::TYPES[:uncompressed]).to_point
|
282
282
|
p2 = Tapyrus::Key.new(pubkey: pubkey, key_type: key_type).to_point
|
@@ -314,9 +314,9 @@ module Tapyrus
|
|
314
314
|
ext_pubkey = ExtPubkey.new
|
315
315
|
ext_pubkey.ver = buf.read(4).bth # version
|
316
316
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_VERSION unless ExtPubkey.support_version?(ext_pubkey.ver)
|
317
|
-
ext_pubkey.depth = buf.read(1).unpack(
|
317
|
+
ext_pubkey.depth = buf.read(1).unpack("C").first
|
318
318
|
ext_pubkey.parent_fingerprint = buf.read(4).bth
|
319
|
-
ext_pubkey.number = buf.read(4).unpack(
|
319
|
+
ext_pubkey.number = buf.read(4).unpack("N").first
|
320
320
|
if ext_pubkey.depth == 0
|
321
321
|
unless ext_pubkey.parent_fingerprint == ExtKey::MASTER_FINGERPRINT
|
322
322
|
raise ArgumentError, Errors::Messages::INVALID_BIP32_FINGERPRINT
|
@@ -365,7 +365,7 @@ module Tapyrus
|
|
365
365
|
end
|
366
366
|
|
367
367
|
def master?
|
368
|
-
depth == 0 && number == 0 && parent_fingerprint ==
|
368
|
+
depth == 0 && number == 0 && parent_fingerprint == "00000000"
|
369
369
|
end
|
370
370
|
end
|
371
371
|
end
|
data/lib/tapyrus/jws.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
module JWS
|
3
|
+
module_function
|
4
|
+
|
5
|
+
class DecodeError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
ALGO = "ES256K"
|
9
|
+
CURVE_NAME = "secp256k1"
|
10
|
+
|
11
|
+
# Encode data as JWS format.
|
12
|
+
#
|
13
|
+
# @param payload [Object] The data to be encoded as JWS.
|
14
|
+
# @param private_key_hex [String] The private key as hex string
|
15
|
+
# @return [String] JWS signed with the specified private key
|
16
|
+
def encode(payload, private_key_hex)
|
17
|
+
parameters = { use: "sig", alg: ALGO }
|
18
|
+
|
19
|
+
# see https://github.com/nov/json-jwt/blob/413848c/lib/json/jwk.rb#L162-L172
|
20
|
+
# see https://www.rfc-editor.org/rfc/rfc5915.html#page-6
|
21
|
+
sequence =
|
22
|
+
OpenSSL::ASN1.Sequence(
|
23
|
+
[
|
24
|
+
OpenSSL::ASN1.Integer(1),
|
25
|
+
OpenSSL::ASN1.OctetString(OpenSSL::BN.new(private_key_hex, 16).to_s(2)),
|
26
|
+
OpenSSL::ASN1.ObjectId(CURVE_NAME, 0, :EXPLICIT),
|
27
|
+
OpenSSL::ASN1.BitString(
|
28
|
+
ECDSA::Format::PointOctetString.encode(point_for(private_key_hex), compression: false),
|
29
|
+
1,
|
30
|
+
:EXPLICIT
|
31
|
+
)
|
32
|
+
]
|
33
|
+
)
|
34
|
+
ec_key = OpenSSL::PKey::EC.new(sequence.to_der)
|
35
|
+
jwk = JWT::JWK.new(ec_key, parameters)
|
36
|
+
jwks_hash = JWT::JWK::Set.new(jwk).export(include_private: false)
|
37
|
+
JWT.encode(payload, jwk.signing_key, jwk[:alg], { typ: "JWT", algo: ALGO, jwk: jwks_hash })
|
38
|
+
end
|
39
|
+
|
40
|
+
# Decode JWS to JSON object
|
41
|
+
#
|
42
|
+
# @param jws [String] The JWS formatted data to be decoded
|
43
|
+
# @return [Array[JSON]] JSON objects representing JWS header and payload.
|
44
|
+
# @raise [JWT::VerificationError] If the verification of the signature fails
|
45
|
+
# @raise [Tapyrus::JWS::DecodeError] If no jwk key found in header
|
46
|
+
# @raise [Tapyrus::JWS::DecodeError] If jwk kty header is not EC
|
47
|
+
# @raise [Tapyrus::JWS::DecodeError] If jwk crv header is not P-256K
|
48
|
+
# @raise [Tapyrus::JWS::DecodeError] If jwk use header is not sig
|
49
|
+
# @raise [Tapyrus::JWS::DecodeError] If jwk alg header is not ES256K
|
50
|
+
def decode(jws)
|
51
|
+
jwt_claims, header = JWT.decode(jws, nil, false, { algorithm: ALGO })
|
52
|
+
jwks_hash = header.dig("jwk", "keys")
|
53
|
+
raise Tapyrus::JWS::DecodeError, "No jwk key found in header" unless jwks_hash
|
54
|
+
validate_header!(jwks_hash)
|
55
|
+
jwks = JWT::JWK::Set.new(jwks_hash)
|
56
|
+
JWT.decode(jws, nil, true, { algorithm: ALGO, jwks: jwks, allow_nil_kid: true })
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_header!(jwks)
|
60
|
+
jwk = jwks.first
|
61
|
+
raise Tapyrus::JWS::DecodeError, "No jwk key found in header" unless jwk
|
62
|
+
raise Tapyrus::JWS::DecodeError, 'kty must be "EC"' if jwk["kty"] && jwk["kty"] != "EC"
|
63
|
+
raise Tapyrus::JWS::DecodeError, 'crv must be "P-256K"' if jwk["crv"] && jwk["crv"] != "P-256K"
|
64
|
+
raise Tapyrus::JWS::DecodeError, 'use must be "sig"' if jwk["use"] && jwk["use"] != "sig"
|
65
|
+
raise Tapyrus::JWS::DecodeError, 'alg must be "ES256K"' if jwk["alg"] && jwk["alg"] != "ES256K"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return point object that represents rG
|
69
|
+
#
|
70
|
+
# @param r_hex [String] r value as hex string
|
71
|
+
# @return [ECDSA::Point] The point that represents r * G
|
72
|
+
def point_for(r_hex)
|
73
|
+
Tapyrus::Key.new(priv_key: r_hex).to_point
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/tapyrus/key.rb
CHANGED
@@ -9,7 +9,7 @@ module Tapyrus
|
|
9
9
|
SIGNATURE_SIZE = 72
|
10
10
|
COMPACT_SIGNATURE_SIZE = 65
|
11
11
|
|
12
|
-
SIG_ALGO = [
|
12
|
+
SIG_ALGO = %i[ecdsa schnorr]
|
13
13
|
|
14
14
|
attr_accessor :priv_key
|
15
15
|
attr_accessor :pubkey
|
@@ -31,7 +31,7 @@ module Tapyrus
|
|
31
31
|
# @return [Tapyrus::Key] a key object.
|
32
32
|
def initialize(priv_key: nil, pubkey: nil, key_type: nil, compressed: true, allow_hybrid: false)
|
33
33
|
if key_type.nil? && !compressed.nil? && pubkey.nil?
|
34
|
-
warn(
|
34
|
+
warn("Use key_type parameter instead of compressed. compressed parameter removed in the future.")
|
35
35
|
end
|
36
36
|
if key_type
|
37
37
|
@key_type = key_type
|
@@ -56,7 +56,7 @@ module Tapyrus
|
|
56
56
|
|
57
57
|
# generate key pair
|
58
58
|
def self.generate(key_type = TYPES[:compressed])
|
59
|
-
priv_key, pubkey = Tapyrus.secp_impl.generate_key_pair
|
59
|
+
priv_key, pubkey = Tapyrus.secp_impl.generate_key_pair(compressed: key_type != TYPES[:uncompressed])
|
60
60
|
new(priv_key: priv_key, pubkey: pubkey, key_type: key_type)
|
61
61
|
end
|
62
62
|
|
@@ -64,22 +64,22 @@ module Tapyrus
|
|
64
64
|
# https://en.bitcoin.it/wiki/Wallet_import_format
|
65
65
|
def self.from_wif(wif)
|
66
66
|
hex = Base58.decode(wif)
|
67
|
-
raise ArgumentError,
|
67
|
+
raise ArgumentError, "data is too short" if hex.htb.bytesize < 4
|
68
68
|
version = hex[0..1]
|
69
69
|
data = hex[2...-8].htb
|
70
70
|
checksum = hex[-8..-1]
|
71
|
-
raise ArgumentError,
|
71
|
+
raise ArgumentError, "invalid version" unless version == Tapyrus.chain_params.privkey_version
|
72
72
|
unless Tapyrus.calc_checksum(version + data.bth) == checksum
|
73
73
|
raise ArgumentError, Errors::Messages::INVALID_CHECKSUM
|
74
74
|
end
|
75
75
|
key_len = data.bytesize
|
76
|
-
if key_len == COMPRESSED_PUBLIC_KEY_SIZE && data[-1].unpack(
|
76
|
+
if key_len == COMPRESSED_PUBLIC_KEY_SIZE && data[-1].unpack("C").first == 1
|
77
77
|
key_type = TYPES[:compressed]
|
78
78
|
data = data[0..-2]
|
79
79
|
elsif key_len == 32
|
80
80
|
key_type = TYPES[:uncompressed]
|
81
81
|
else
|
82
|
-
raise ArgumentError,
|
82
|
+
raise ArgumentError, "Wrong number of bytes for a private key, not 32 or 33"
|
83
83
|
end
|
84
84
|
new(priv_key: data.bth, key_type: key_type)
|
85
85
|
end
|
@@ -88,7 +88,7 @@ module Tapyrus
|
|
88
88
|
def to_wif
|
89
89
|
version = Tapyrus.chain_params.privkey_version
|
90
90
|
hex = version + priv_key
|
91
|
-
hex +=
|
91
|
+
hex += "01" if compressed?
|
92
92
|
hex += Tapyrus.calc_checksum(hex)
|
93
93
|
Base58.encode(hex)
|
94
94
|
end
|
@@ -100,7 +100,7 @@ module Tapyrus
|
|
100
100
|
# @param [Symbol] algo Algorithms used for verification. Either :ecdsa or :schnorr is supported. default value is :ecdsa.
|
101
101
|
# @return [String] signature data with binary format
|
102
102
|
def sign(data, low_r = true, extra_entropy = nil, algo: :ecdsa)
|
103
|
-
raise ArgumentError,
|
103
|
+
raise ArgumentError, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
|
104
104
|
case algo
|
105
105
|
when :ecdsa
|
106
106
|
sign_ecdsa(data, low_r, extra_entropy)
|
@@ -119,7 +119,7 @@ module Tapyrus
|
|
119
119
|
def verify(sig, origin, algo: :ecdsa)
|
120
120
|
return false unless valid_pubkey?
|
121
121
|
begin
|
122
|
-
raise ArgumentError,
|
122
|
+
raise ArgumentError, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
|
123
123
|
sig = ecdsa_signature_parse_der_lax(sig) if algo == :ecdsa
|
124
124
|
secp256k1_module.verify_sig(origin, sig, pubkey, algo: algo)
|
125
125
|
rescue Exception
|
@@ -173,17 +173,45 @@ module Tapyrus
|
|
173
173
|
|
174
174
|
# check +sig+ is low.
|
175
175
|
def self.low_signature?(sig)
|
176
|
-
s = sig.unpack(
|
176
|
+
s = sig.unpack("C*")
|
177
177
|
len_r = s[3]
|
178
178
|
len_s = s[5 + len_r]
|
179
179
|
val_s = s.slice(6 + len_r, len_s)
|
180
180
|
|
181
181
|
# prettier-ignore
|
182
182
|
max_mod_half_order = [
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
183
|
+
0x7f,
|
184
|
+
0xff,
|
185
|
+
0xff,
|
186
|
+
0xff,
|
187
|
+
0xff,
|
188
|
+
0xff,
|
189
|
+
0xff,
|
190
|
+
0xff,
|
191
|
+
0xff,
|
192
|
+
0xff,
|
193
|
+
0xff,
|
194
|
+
0xff,
|
195
|
+
0xff,
|
196
|
+
0xff,
|
197
|
+
0xff,
|
198
|
+
0xff,
|
199
|
+
0x5d,
|
200
|
+
0x57,
|
201
|
+
0x6e,
|
202
|
+
0x73,
|
203
|
+
0x57,
|
204
|
+
0xa4,
|
205
|
+
0x50,
|
206
|
+
0x1d,
|
207
|
+
0xdf,
|
208
|
+
0xe9,
|
209
|
+
0x2f,
|
210
|
+
0x46,
|
211
|
+
0x68,
|
212
|
+
0x1b,
|
213
|
+
0x20,
|
214
|
+
0xa0
|
187
215
|
]
|
188
216
|
compare_big_endian(val_s, [0]) > 0 && compare_big_endian(val_s, max_mod_half_order) <= 0
|
189
217
|
end
|
@@ -199,7 +227,7 @@ module Tapyrus
|
|
199
227
|
|
200
228
|
return false if sig.bytesize < num_parts || sig.bytesize > size # Minimum and maximum size check
|
201
229
|
|
202
|
-
s = sig.unpack(
|
230
|
+
s = sig.unpack("C*")
|
203
231
|
|
204
232
|
return false if s[0] != 0x30 || s[1] != s.size - (data_sig ? 2 : 3) # A signature is of type 0x30 (compound). Make sure the length covers the entire signature.
|
205
233
|
|
@@ -267,11 +295,11 @@ module Tapyrus
|
|
267
295
|
# strict DER before being passed to this module, and we know it supports all
|
268
296
|
# violations present in the blockchain before that point.
|
269
297
|
def ecdsa_signature_parse_der_lax(sig)
|
270
|
-
sig_array = sig.unpack(
|
298
|
+
sig_array = sig.unpack("C*")
|
271
299
|
len_r = sig_array[3]
|
272
|
-
r = sig_array[4...(len_r + 4)].pack(
|
300
|
+
r = sig_array[4...(len_r + 4)].pack("C*").bth
|
273
301
|
len_s = sig_array[len_r + 5]
|
274
|
-
s = sig_array[(len_r + 6)...(len_r + 6 + len_s)].pack(
|
302
|
+
s = sig_array[(len_r + 6)...(len_r + 6 + len_s)].pack("C*").bth
|
275
303
|
ECDSA::Signature.new(r.to_i(16), s.to_i(16)).to_der
|
276
304
|
end
|
277
305
|
|
@@ -292,7 +320,7 @@ module Tapyrus
|
|
292
320
|
if low_r && !sig_has_low_r?(sig)
|
293
321
|
counter = 1
|
294
322
|
until sig_has_low_r?(sig)
|
295
|
-
extra_entropy = [counter].pack(
|
323
|
+
extra_entropy = [counter].pack("I*").bth.ljust(64, "0").htb
|
296
324
|
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :ecdsa)
|
297
325
|
counter += 1
|
298
326
|
end
|
data/lib/tapyrus/key_path.rb
CHANGED
@@ -5,11 +5,11 @@ module Tapyrus
|
|
5
5
|
# @return [Array[Integer]] key path numbers.
|
6
6
|
def parse_key_path(path_string)
|
7
7
|
path_string
|
8
|
-
.split(
|
8
|
+
.split("/")
|
9
9
|
.map
|
10
10
|
.with_index do |p, index|
|
11
11
|
if index == 0
|
12
|
-
raise ArgumentError.new("#{path_string} is invalid format.") unless p ==
|
12
|
+
raise ArgumentError.new("#{path_string} is invalid format.") unless p == "m"
|
13
13
|
next
|
14
14
|
end
|
15
15
|
raise ArgumentError.new("#{path_string} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
|
@@ -23,7 +23,7 @@ module Tapyrus
|
|
23
23
|
# @param [Array[Integer]] key path numbers.
|
24
24
|
# @return [String] path string.
|
25
25
|
def to_key_path(numbers)
|
26
|
-
"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("/")}"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/lib/tapyrus/logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "logger"
|
2
2
|
|
3
3
|
module Tapyrus
|
4
4
|
# Simple Logger module
|
@@ -15,15 +15,8 @@ module Tapyrus
|
|
15
15
|
logger.level = level
|
16
16
|
logger.formatter =
|
17
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
|
-
]
|
18
|
+
Format %
|
19
|
+
[severity[0..0], format_datetime(datetime), $$, Thread.current.object_id, severity, progname, msg2str(msg)]
|
27
20
|
end
|
28
21
|
logger
|
29
22
|
end
|
@@ -40,7 +33,7 @@ module Tapyrus
|
|
40
33
|
end
|
41
34
|
|
42
35
|
def format_datetime(time)
|
43
|
-
time.strftime(@datetime_format ||
|
36
|
+
time.strftime(@datetime_format || "%Y-%m-%dT%H:%M:%S.%6N ".freeze)
|
44
37
|
end
|
45
38
|
end
|
46
39
|
end
|
data/lib/tapyrus/merkle_tree.rb
CHANGED
data/lib/tapyrus/message/addr.rb
CHANGED
data/lib/tapyrus/message/base.rb
CHANGED
@@ -12,14 +12,14 @@ module Tapyrus
|
|
12
12
|
payload = to_payload
|
13
13
|
magic = Tapyrus.chain_params.magic_head.htb
|
14
14
|
command_name = self.class.const_get(:COMMAND, false).ljust(12, "\x00")
|
15
|
-
payload_size = [payload.bytesize].pack(
|
15
|
+
payload_size = [payload.bytesize].pack("V")
|
16
16
|
checksum = Tapyrus.double_sha256(payload)[0...4]
|
17
17
|
magic << command_name << payload_size << checksum << payload
|
18
18
|
end
|
19
19
|
|
20
20
|
# abstract method
|
21
21
|
def to_payload
|
22
|
-
raise
|
22
|
+
raise "to_payload must be implemented in a child class."
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -3,7 +3,7 @@ module Tapyrus
|
|
3
3
|
# feefilter message
|
4
4
|
# https://bitcoin.org/en/developer-reference#feefilter
|
5
5
|
class FeeFilter < Base
|
6
|
-
COMMAND =
|
6
|
+
COMMAND = "feefilter"
|
7
7
|
|
8
8
|
# The fee rate (in satoshis per kilobyte)
|
9
9
|
attr_accessor :fee_rate
|
@@ -13,11 +13,11 @@ module Tapyrus
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.parse_from_payload(payload)
|
16
|
-
new(payload.unpack(
|
16
|
+
new(payload.unpack("Q").first)
|
17
17
|
end
|
18
18
|
|
19
19
|
def to_payload
|
20
|
-
[fee_rate].pack(
|
20
|
+
[fee_rate].pack("Q")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -3,7 +3,7 @@ module Tapyrus
|
|
3
3
|
# filteradd message
|
4
4
|
# https://bitcoin.org/en/developer-reference#filteradd
|
5
5
|
class FilterAdd < Base
|
6
|
-
COMMAND =
|
6
|
+
COMMAND = "filteradd"
|
7
7
|
|
8
8
|
# element must be sent in the byte order they would use when appearing in a raw transaction;
|
9
9
|
attr_accessor :element
|
@@ -3,7 +3,7 @@ module Tapyrus
|
|
3
3
|
# filterload message
|
4
4
|
# https://bitcoin.org/en/developer-reference#filterload
|
5
5
|
class FilterLoad < Base
|
6
|
-
COMMAND =
|
6
|
+
COMMAND = "filterload"
|
7
7
|
|
8
8
|
BLOOM_UPDATE_NONE = 0
|
9
9
|
BLOOM_UPDATE_ALL = 1
|
@@ -20,16 +20,16 @@ module Tapyrus
|
|
20
20
|
def self.parse_from_payload(payload)
|
21
21
|
buf = StringIO.new(payload)
|
22
22
|
filter_count = Tapyrus.unpack_var_int_from_io(buf)
|
23
|
-
filter = buf.read(filter_count).unpack(
|
24
|
-
func_count = buf.read(4).unpack(
|
25
|
-
tweak = buf.read(4).unpack(
|
26
|
-
flag = buf.read(1).unpack(
|
23
|
+
filter = buf.read(filter_count).unpack("C*")
|
24
|
+
func_count = buf.read(4).unpack("V").first
|
25
|
+
tweak = buf.read(4).unpack("V").first
|
26
|
+
flag = buf.read(1).unpack("C").first
|
27
27
|
FilterLoad.new(Tapyrus::BloomFilter.new(filter, func_count, tweak), flag)
|
28
28
|
end
|
29
29
|
|
30
30
|
def to_payload
|
31
|
-
Tapyrus.pack_var_int(filter.filter.size) << filter.filter.pack(
|
32
|
-
[filter.hash_funcs, filter.tweak, flag].pack(
|
31
|
+
Tapyrus.pack_var_int(filter.filter.size) << filter.filter.pack("C*") <<
|
32
|
+
[filter.hash_funcs, filter.tweak, flag].pack("VVC")
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|