tapyrus 0.3.4 → 0.3.5
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 +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
|
@@ -46,7 +46,7 @@ module Tapyrus
|
|
|
46
46
|
# @return [Script] CP2PKH script
|
|
47
47
|
# @raise [ArgumentError] if color_id is nil or invalid
|
|
48
48
|
def self.to_cp2pkh(color_id, pubkey_hash)
|
|
49
|
-
raise ArgumentError,
|
|
49
|
+
raise ArgumentError, "Specified color identifier is invalid" unless color_id&.valid?
|
|
50
50
|
new << color_id.to_payload << OP_COLOR << OP_DUP << OP_HASH160 << pubkey_hash << OP_EQUALVERIFY << OP_CHECKSIG
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ module Tapyrus
|
|
|
56
56
|
# @return [Script] CP2SH script
|
|
57
57
|
# @raise [ArgumentError] if color_id is nil or invalid
|
|
58
58
|
def self.to_cp2sh(color_id, script_hash)
|
|
59
|
-
raise ArgumentError,
|
|
59
|
+
raise ArgumentError, "Specified color identifier is invalid" unless color_id&.valid?
|
|
60
60
|
new << color_id.to_payload << OP_COLOR << OP_HASH160 << script_hash << OP_EQUAL
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -66,8 +66,8 @@ module Tapyrus
|
|
|
66
66
|
# @raise [ArgumentError] if color_id is nil or invalid
|
|
67
67
|
# @raise [RuntimeError] if script is neither p2pkh nor p2sh
|
|
68
68
|
def add_color(color_id)
|
|
69
|
-
raise ArgumentError,
|
|
70
|
-
raise RuntimeError,
|
|
69
|
+
raise ArgumentError, "Specified color identifier is invalid" unless color_id&.valid?
|
|
70
|
+
raise RuntimeError, "Only p2pkh and p2sh can add color" unless p2pkh? or p2sh?
|
|
71
71
|
Tapyrus::Script.new.tap do |s|
|
|
72
72
|
s << color_id.to_payload << OP_COLOR
|
|
73
73
|
s.chunks += self.chunks
|
|
@@ -78,7 +78,7 @@ module Tapyrus
|
|
|
78
78
|
# @return [Script] P2PKH or P2SH script
|
|
79
79
|
# @raise [RuntimeError] if script is neither cp2pkh nor cp2sh
|
|
80
80
|
def remove_color
|
|
81
|
-
raise RuntimeError,
|
|
81
|
+
raise RuntimeError, "Only cp2pkh and cp2sh can remove color" unless cp2pkh? or cp2sh?
|
|
82
82
|
|
|
83
83
|
Tapyrus::Script.new.tap { |s| s.chunks = self.chunks[2..-1] }
|
|
84
84
|
end
|
|
@@ -101,7 +101,7 @@ module Tapyrus
|
|
|
101
101
|
def self.from_string(string)
|
|
102
102
|
script = new
|
|
103
103
|
string
|
|
104
|
-
.split(
|
|
104
|
+
.split(" ")
|
|
105
105
|
.each do |v|
|
|
106
106
|
opcode = Opcodes.name_to_opcode(v)
|
|
107
107
|
if opcode
|
|
@@ -144,18 +144,18 @@ module Tapyrus
|
|
|
144
144
|
case pushcode
|
|
145
145
|
when OP_PUSHDATA1
|
|
146
146
|
packed_size = buf.read(1)
|
|
147
|
-
packed_size.unpack(
|
|
147
|
+
packed_size.unpack("C").first
|
|
148
148
|
when OP_PUSHDATA2
|
|
149
149
|
packed_size = buf.read(2)
|
|
150
|
-
packed_size.unpack(
|
|
150
|
+
packed_size.unpack("v").first
|
|
151
151
|
when OP_PUSHDATA4
|
|
152
152
|
packed_size = buf.read(4)
|
|
153
|
-
packed_size.unpack(
|
|
153
|
+
packed_size.unpack("V").first
|
|
154
154
|
else
|
|
155
155
|
pushcode if pushcode < OP_PUSHDATA1
|
|
156
156
|
end
|
|
157
157
|
if len
|
|
158
|
-
s.chunks << [len].pack(
|
|
158
|
+
s.chunks << [len].pack("C") if buf.eof?
|
|
159
159
|
unless buf.eof?
|
|
160
160
|
chunk = (packed_size ? (opcode + packed_size) : (opcode)) + buf.read(len)
|
|
161
161
|
s.chunks << chunk
|
|
@@ -374,11 +374,11 @@ module Tapyrus
|
|
|
374
374
|
end
|
|
375
375
|
else
|
|
376
376
|
opcode = Opcodes.opcode_to_name(c.ord)
|
|
377
|
-
opcode ? opcode :
|
|
377
|
+
opcode ? opcode : "OP_UNKNOWN [error]"
|
|
378
378
|
end
|
|
379
379
|
end
|
|
380
380
|
end
|
|
381
|
-
.join(
|
|
381
|
+
.join(" ")
|
|
382
382
|
end
|
|
383
383
|
|
|
384
384
|
# generate sha-256 hash for payload
|
|
@@ -410,15 +410,15 @@ module Tapyrus
|
|
|
410
410
|
# Byte vectors are interpreted as Booleans where False is represented by any representation of zero,
|
|
411
411
|
# and True is represented by any representation of non-zero.
|
|
412
412
|
def self.encode_number(i)
|
|
413
|
-
return
|
|
413
|
+
return "" if i == 0
|
|
414
414
|
negative = i < 0
|
|
415
415
|
|
|
416
416
|
hex = i.abs.to_even_length_hex
|
|
417
|
-
hex =
|
|
417
|
+
hex = "0" + hex unless (hex.length % 2).zero?
|
|
418
418
|
v = hex.htb.reverse # change endian
|
|
419
419
|
|
|
420
|
-
v = v << (negative ? 0x80 : 0x00) unless (v[-1].unpack(
|
|
421
|
-
v[-1] = [v[-1].unpack(
|
|
420
|
+
v = v << (negative ? 0x80 : 0x00) unless (v[-1].unpack("C").first & 0x80) == 0
|
|
421
|
+
v[-1] = [v[-1].unpack("C").first | 0x80].pack("C") if negative
|
|
422
422
|
v.bth
|
|
423
423
|
end
|
|
424
424
|
|
|
@@ -426,8 +426,8 @@ module Tapyrus
|
|
|
426
426
|
def self.decode_number(s)
|
|
427
427
|
v = s.htb.reverse
|
|
428
428
|
return 0 if v.length.zero?
|
|
429
|
-
mbs = v[0].unpack(
|
|
430
|
-
v[0] = [mbs - 0x80].pack(
|
|
429
|
+
mbs = v[0].unpack("C").first
|
|
430
|
+
v[0] = [mbs - 0x80].pack("C") unless (mbs & 0x80) == 0
|
|
431
431
|
result = v.bth.to_i(16)
|
|
432
432
|
result = -result unless (mbs & 0x80) == 0
|
|
433
433
|
result
|
|
@@ -438,15 +438,15 @@ module Tapyrus
|
|
|
438
438
|
size = data.bytesize
|
|
439
439
|
header =
|
|
440
440
|
if size < OP_PUSHDATA1
|
|
441
|
-
[size].pack(
|
|
441
|
+
[size].pack("C")
|
|
442
442
|
elsif size < 0xff
|
|
443
|
-
[OP_PUSHDATA1, size].pack(
|
|
443
|
+
[OP_PUSHDATA1, size].pack("CC")
|
|
444
444
|
elsif size < 0xffff
|
|
445
|
-
[OP_PUSHDATA2, size].pack(
|
|
445
|
+
[OP_PUSHDATA2, size].pack("Cv")
|
|
446
446
|
elsif size < 0xffffffff
|
|
447
|
-
[OP_PUSHDATA4, size].pack(
|
|
447
|
+
[OP_PUSHDATA4, size].pack("CV")
|
|
448
448
|
else
|
|
449
|
-
raise ArgumentError,
|
|
449
|
+
raise ArgumentError, "data size is too big."
|
|
450
450
|
end
|
|
451
451
|
header + data
|
|
452
452
|
end
|
|
@@ -460,7 +460,7 @@ module Tapyrus
|
|
|
460
460
|
|
|
461
461
|
# removes chunks matching subscript byte-for-byte and returns as a new object.
|
|
462
462
|
def find_and_delete(subscript)
|
|
463
|
-
raise ArgumentError,
|
|
463
|
+
raise ArgumentError, "subscript must be Tapyrus::Script" unless subscript.is_a?(Script)
|
|
464
464
|
return self if subscript.chunks.empty?
|
|
465
465
|
buf = []
|
|
466
466
|
i = 0
|
|
@@ -519,10 +519,10 @@ module Tapyrus
|
|
|
519
519
|
end
|
|
520
520
|
|
|
521
521
|
def type
|
|
522
|
-
return
|
|
523
|
-
return
|
|
524
|
-
return
|
|
525
|
-
|
|
522
|
+
return "pubkeyhash" if p2pkh?
|
|
523
|
+
return "scripthash" if p2sh?
|
|
524
|
+
return "multisig" if multisig?
|
|
525
|
+
"nonstandard"
|
|
526
526
|
end
|
|
527
527
|
|
|
528
528
|
def to_h
|
|
@@ -4,8 +4,8 @@ module Tapyrus
|
|
|
4
4
|
attr_accessor :code
|
|
5
5
|
attr_accessor :extra_msg
|
|
6
6
|
|
|
7
|
-
def initialize(code, extra_msg =
|
|
8
|
-
raise
|
|
7
|
+
def initialize(code, extra_msg = "")
|
|
8
|
+
raise "invalid error code." unless ERRCODES_MAP[code]
|
|
9
9
|
@code = code
|
|
10
10
|
@extra_msg = extra_msg
|
|
11
11
|
end
|
|
@@ -13,85 +13,85 @@ module Tapyrus
|
|
|
13
13
|
def to_s
|
|
14
14
|
case code
|
|
15
15
|
when SCRIPT_ERR_OK
|
|
16
|
-
|
|
16
|
+
"No error"
|
|
17
17
|
when SCRIPT_ERR_EVAL_FALSE
|
|
18
|
-
|
|
18
|
+
"Script evaluated without error but finished with a false/empty top stack element"
|
|
19
19
|
when SCRIPT_ERR_VERIFY
|
|
20
|
-
|
|
20
|
+
"Script failed an OP_VERIFY operation"
|
|
21
21
|
when SCRIPT_ERR_EQUALVERIFY
|
|
22
|
-
|
|
22
|
+
"Script failed an OP_EQUALVERIFY operation"
|
|
23
23
|
when SCRIPT_ERR_CHECKMULTISIGVERIFY
|
|
24
|
-
|
|
24
|
+
"Script failed an OP_CHECKMULTISIGVERIFY operation"
|
|
25
25
|
when SCRIPT_ERR_CHECKSIGVERIFY
|
|
26
|
-
|
|
26
|
+
"Script failed an OP_CHECKSIGVERIFY operation"
|
|
27
27
|
when SCRIPT_ERR_NUMEQUALVERIFY
|
|
28
|
-
|
|
28
|
+
"Script failed an OP_NUMEQUALVERIFY operation"
|
|
29
29
|
when SCRIPT_ERR_SCRIPT_SIZE
|
|
30
|
-
|
|
30
|
+
"Script is too big"
|
|
31
31
|
when SCRIPT_ERR_PUSH_SIZE
|
|
32
|
-
|
|
32
|
+
"Push value size limit exceeded"
|
|
33
33
|
when SCRIPT_ERR_OP_COUNT
|
|
34
|
-
|
|
34
|
+
"Operation limit exceeded"
|
|
35
35
|
when SCRIPT_ERR_STACK_SIZE
|
|
36
|
-
|
|
36
|
+
"Stack size limit exceeded"
|
|
37
37
|
when SCRIPT_ERR_SIG_COUNT
|
|
38
|
-
|
|
38
|
+
"Signature count negative or greater than pubkey count"
|
|
39
39
|
when SCRIPT_ERR_PUBKEY_COUNT
|
|
40
|
-
|
|
40
|
+
"Pubkey count negative or limit exceeded"
|
|
41
41
|
when SCRIPT_ERR_BAD_OPCODE
|
|
42
|
-
|
|
42
|
+
"Opcode missing or not understood"
|
|
43
43
|
when SCRIPT_ERR_DISABLED_OPCODE
|
|
44
|
-
|
|
44
|
+
"Attempted to use a disabled opcode"
|
|
45
45
|
when SCRIPT_ERR_INVALID_STACK_OPERATION
|
|
46
|
-
|
|
46
|
+
"Operation not valid with the current stack size"
|
|
47
47
|
when SCRIPT_ERR_INVALID_ALTSTACK_OPERATION
|
|
48
|
-
|
|
48
|
+
"Operation not valid with the current altstack size"
|
|
49
49
|
when SCRIPT_ERR_OP_RETURN
|
|
50
|
-
|
|
50
|
+
"OP_was encountered"
|
|
51
51
|
when SCRIPT_ERR_UNBALANCED_CONDITIONAL
|
|
52
|
-
|
|
52
|
+
"Invalid OP_IF construction"
|
|
53
53
|
when SCRIPT_ERR_NEGATIVE_LOCKTIME
|
|
54
|
-
|
|
54
|
+
"Negative locktime"
|
|
55
55
|
when SCRIPT_ERR_UNSATISFIED_LOCKTIME
|
|
56
|
-
|
|
56
|
+
"Locktime requirement not satisfied"
|
|
57
57
|
when SCRIPT_ERR_SIG_HASHTYPE
|
|
58
|
-
|
|
58
|
+
"Signature hash type missing or not understood"
|
|
59
59
|
when SCRIPT_ERR_SIG_DER
|
|
60
|
-
|
|
60
|
+
"Non-canonical DER signature"
|
|
61
61
|
when SCRIPT_ERR_MINIMALDATA
|
|
62
|
-
|
|
62
|
+
"Data push larger than necessary"
|
|
63
63
|
when SCRIPT_ERR_SIG_PUSHONLY
|
|
64
|
-
|
|
64
|
+
"Only non-push operators allowed in signatures"
|
|
65
65
|
when SCRIPT_ERR_SIG_HIGH_S
|
|
66
|
-
|
|
66
|
+
"Non-canonical signature S value is unnecessarily high"
|
|
67
67
|
when SCRIPT_ERR_SIG_NULLDUMMY
|
|
68
|
-
|
|
68
|
+
"Dummy CHECKMULTISIG argument must be zero"
|
|
69
69
|
when SCRIPT_ERR_MINIMALIF
|
|
70
|
-
|
|
70
|
+
"OP_IF/NOTIF argument must be minimal"
|
|
71
71
|
when SCRIPT_ERR_SIG_NULLFAIL
|
|
72
|
-
|
|
72
|
+
"Signature must be zero for failed CHECK(MULTI)SIG operation"
|
|
73
73
|
when SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS
|
|
74
|
-
|
|
74
|
+
"NOPx reserved for soft-fork upgrades"
|
|
75
75
|
when SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM
|
|
76
|
-
|
|
76
|
+
"Witness version reserved for soft-fork upgrades"
|
|
77
77
|
when SCRIPT_ERR_PUBKEYTYPE
|
|
78
|
-
|
|
78
|
+
"Public key is neither compressed or uncompressed"
|
|
79
79
|
when SCRIPT_ERR_OP_CODESEPARATOR
|
|
80
|
-
|
|
80
|
+
"Using OP_CODESEPARATOR in non-witness scrip"
|
|
81
81
|
when SCRIPT_ERR_SIG_FINDANDDELETE
|
|
82
|
-
|
|
82
|
+
"Signature is found in scriptCode"
|
|
83
83
|
when SCRIPT_ERR_OP_COLOR_UNEXPECTED
|
|
84
|
-
|
|
84
|
+
"Unexpected OP_COLOR in script"
|
|
85
85
|
when SCRIPT_ERR_OP_COLOR_ID_INVALID
|
|
86
|
-
|
|
86
|
+
"Invalid ColorId in script"
|
|
87
87
|
when SCRIPT_ERR_OP_COLOR_MULTIPLE
|
|
88
|
-
|
|
88
|
+
"Multiple OP_COLOR found in script"
|
|
89
89
|
when SCRIPT_ERR_OP_COLOR_IN_BRANCH
|
|
90
|
-
|
|
90
|
+
"OP_COLOR is not permitted in a script branch"
|
|
91
91
|
when SCRIPT_ERR_UNKNOWN_ERROR, SCRIPT_ERR_ERROR_COUNT
|
|
92
|
-
|
|
92
|
+
"unknown error"
|
|
93
93
|
else
|
|
94
|
-
extra_msg ? extra_msg :
|
|
94
|
+
extra_msg ? extra_msg : "unknown error"
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -70,7 +70,7 @@ module Tapyrus
|
|
|
70
70
|
return set_error(SCRIPT_ERR_SIG_PUSHONLY) unless script_sig.push_only?
|
|
71
71
|
tmp = stack
|
|
72
72
|
@stack = stack_copy
|
|
73
|
-
raise
|
|
73
|
+
raise "stack cannot be empty." if stack.empty?
|
|
74
74
|
begin
|
|
75
75
|
redeem_script = Tapyrus::Script.parse_from_payload(stack.pop.htb)
|
|
76
76
|
rescue Exception => e
|
|
@@ -86,7 +86,7 @@ module Tapyrus
|
|
|
86
86
|
if flag?(SCRIPT_VERIFY_CLEANSTACK)
|
|
87
87
|
# Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK would be possible,
|
|
88
88
|
# which is not a softfork (and P2SH should be one).
|
|
89
|
-
raise
|
|
89
|
+
raise "assert" unless flag?(SCRIPT_VERIFY_P2SH)
|
|
90
90
|
return set_error(SCRIPT_ERR_CLEANSTACK) unless stack.size == 1
|
|
91
91
|
end
|
|
92
92
|
|
|
@@ -146,7 +146,7 @@ module Tapyrus
|
|
|
146
146
|
else
|
|
147
147
|
case opcode
|
|
148
148
|
when OP_0
|
|
149
|
-
stack <<
|
|
149
|
+
stack << ""
|
|
150
150
|
when OP_DEPTH
|
|
151
151
|
push_int(stack.size)
|
|
152
152
|
when OP_EQUAL, OP_EQUALVERIFY
|
|
@@ -184,7 +184,7 @@ module Tapyrus
|
|
|
184
184
|
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if stack.size < 1
|
|
185
185
|
value = pop_string.htb
|
|
186
186
|
if flag?(SCRIPT_VERIFY_MINIMALIF)
|
|
187
|
-
if value.bytesize > 1 || (value.bytesize == 1 && value[0].unpack(
|
|
187
|
+
if value.bytesize > 1 || (value.bytesize == 1 && value[0].unpack("C").first != 1)
|
|
188
188
|
return set_error(SCRIPT_ERR_MINIMALIF)
|
|
189
189
|
end
|
|
190
190
|
end
|
|
@@ -585,7 +585,7 @@ module Tapyrus
|
|
|
585
585
|
raise '"script number overflow"' if data.bytesize > max_num_size
|
|
586
586
|
if require_minimal && data.bytesize > 0
|
|
587
587
|
if data.bytes[-1] & 0x7f == 0 && (data.bytesize <= 1 || data.bytes[data.bytesize - 2] & 0x80 == 0)
|
|
588
|
-
raise
|
|
588
|
+
raise "non-minimally encoded script number"
|
|
589
589
|
end
|
|
590
590
|
end
|
|
591
591
|
Script.decode_number(s)
|
|
@@ -644,7 +644,7 @@ module Tapyrus
|
|
|
644
644
|
def defined_hashtype_signature?(signature)
|
|
645
645
|
sig = signature.htb
|
|
646
646
|
return false if sig.empty?
|
|
647
|
-
s = sig.unpack(
|
|
647
|
+
s = sig.unpack("C*")
|
|
648
648
|
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
|
|
649
649
|
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single]
|
|
650
650
|
true
|
|
@@ -680,13 +680,13 @@ module Tapyrus
|
|
|
680
680
|
case opcode
|
|
681
681
|
when OP_PUSHDATA1
|
|
682
682
|
offset += 1
|
|
683
|
-
buf.read(1).unpack(
|
|
683
|
+
buf.read(1).unpack("C").first
|
|
684
684
|
when OP_PUSHDATA2
|
|
685
685
|
offset += 2
|
|
686
|
-
buf.read(2).unpack(
|
|
686
|
+
buf.read(2).unpack("v").first
|
|
687
687
|
when OP_PUSHDATA4
|
|
688
688
|
offset += 4
|
|
689
|
-
buf.read(4).unpack(
|
|
689
|
+
buf.read(4).unpack("V").first
|
|
690
690
|
else
|
|
691
691
|
opcode
|
|
692
692
|
end
|
|
@@ -16,7 +16,7 @@ module Tapyrus
|
|
|
16
16
|
def check_sig(script_sig, pubkey, script_code)
|
|
17
17
|
return false if script_sig.empty?
|
|
18
18
|
script_sig = script_sig.htb
|
|
19
|
-
hash_type = script_sig[-1].unpack(
|
|
19
|
+
hash_type = script_sig[-1].unpack("C").first
|
|
20
20
|
sig = script_sig[0..-2]
|
|
21
21
|
sighash = tx.sighash_for_input(input_index, script_code, hash_type: hash_type)
|
|
22
22
|
verify_sig(sig.bth, pubkey, sighash)
|
|
@@ -29,7 +29,7 @@ module Tapyrus
|
|
|
29
29
|
# @return [Boolean] if check is passed return true, otherwise false.
|
|
30
30
|
def verify_sig(sig, pubkey, digest, allow_hybrid: false)
|
|
31
31
|
key_type =
|
|
32
|
-
pubkey.start_with?(
|
|
32
|
+
pubkey.start_with?("02") || pubkey.start_with?("03") ? Key::TYPES[:compressed] : Key::TYPES[:uncompressed]
|
|
33
33
|
sig = sig.htb
|
|
34
34
|
algo = sig.bytesize == 64 ? :schnorr : :ecdsa
|
|
35
35
|
begin
|
|
@@ -31,26 +31,26 @@ module Tapyrus
|
|
|
31
31
|
module_function
|
|
32
32
|
|
|
33
33
|
def init
|
|
34
|
-
raise
|
|
35
|
-
ffi_lib(ENV[
|
|
34
|
+
raise "secp256k1 library dose not found." unless File.exist?(ENV["SECP256K1_LIB_PATH"])
|
|
35
|
+
ffi_lib(ENV["SECP256K1_LIB_PATH"])
|
|
36
36
|
load_functions
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def load_functions
|
|
40
40
|
attach_function(:secp256k1_context_create, [:uint], :pointer)
|
|
41
41
|
attach_function(:secp256k1_context_destroy, [:pointer], :void)
|
|
42
|
-
attach_function(:secp256k1_context_randomize, [
|
|
43
|
-
attach_function(:secp256k1_ec_pubkey_create, [
|
|
44
|
-
attach_function(:secp256k1_ec_seckey_verify, [
|
|
45
|
-
attach_function(:secp256k1_ecdsa_sign, [
|
|
46
|
-
attach_function(:secp256k1_ec_pubkey_serialize, [
|
|
47
|
-
attach_function(:secp256k1_ecdsa_signature_serialize_der, [
|
|
48
|
-
attach_function(:secp256k1_ec_pubkey_parse, [
|
|
49
|
-
attach_function(:secp256k1_ecdsa_signature_parse_der, [
|
|
50
|
-
attach_function(:secp256k1_ecdsa_signature_normalize, [
|
|
51
|
-
attach_function(:secp256k1_ecdsa_verify, [
|
|
52
|
-
attach_function(:secp256k1_schnorr_sign, [
|
|
53
|
-
attach_function(:secp256k1_schnorr_verify, [
|
|
42
|
+
attach_function(:secp256k1_context_randomize, %i[pointer pointer], :int)
|
|
43
|
+
attach_function(:secp256k1_ec_pubkey_create, %i[pointer pointer pointer], :int)
|
|
44
|
+
attach_function(:secp256k1_ec_seckey_verify, %i[pointer pointer], :int)
|
|
45
|
+
attach_function(:secp256k1_ecdsa_sign, %i[pointer pointer pointer pointer pointer pointer], :int)
|
|
46
|
+
attach_function(:secp256k1_ec_pubkey_serialize, %i[pointer pointer pointer pointer uint], :int)
|
|
47
|
+
attach_function(:secp256k1_ecdsa_signature_serialize_der, %i[pointer pointer pointer pointer], :int)
|
|
48
|
+
attach_function(:secp256k1_ec_pubkey_parse, %i[pointer pointer pointer size_t], :int)
|
|
49
|
+
attach_function(:secp256k1_ecdsa_signature_parse_der, %i[pointer pointer pointer size_t], :int)
|
|
50
|
+
attach_function(:secp256k1_ecdsa_signature_normalize, %i[pointer pointer pointer], :int)
|
|
51
|
+
attach_function(:secp256k1_ecdsa_verify, %i[pointer pointer pointer pointer], :int)
|
|
52
|
+
attach_function(:secp256k1_schnorr_sign, %i[pointer pointer pointer pointer pointer pointer], :int)
|
|
53
|
+
attach_function(:secp256k1_schnorr_verify, %i[pointer pointer pointer pointer], :int)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def with_context(flags: (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN))
|
|
@@ -59,7 +59,7 @@ module Tapyrus
|
|
|
59
59
|
context = secp256k1_context_create(flags)
|
|
60
60
|
ret, tries, max = 0, 0, 20
|
|
61
61
|
while ret != 1
|
|
62
|
-
raise
|
|
62
|
+
raise "secp256k1_context_randomize failed." if tries >= max
|
|
63
63
|
tries += 1
|
|
64
64
|
ret = secp256k1_context_randomize(context, FFI::MemoryPointer.from_string(SecureRandom.random_bytes(32)))
|
|
65
65
|
end
|
|
@@ -74,7 +74,7 @@ module Tapyrus
|
|
|
74
74
|
with_context do |context|
|
|
75
75
|
ret, tries, max = 0, 0, 20
|
|
76
76
|
while ret != 1
|
|
77
|
-
raise
|
|
77
|
+
raise "secp256k1_ec_seckey_verify in generate_key_pair failed." if tries >= max
|
|
78
78
|
tries += 1
|
|
79
79
|
priv_key = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
|
|
80
80
|
ret = secp256k1_ec_seckey_verify(context, priv_key)
|
|
@@ -145,7 +145,7 @@ module Tapyrus
|
|
|
145
145
|
def generate_pubkey_in_context(context, privkey, compressed: true)
|
|
146
146
|
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
|
147
147
|
result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
|
|
148
|
-
raise
|
|
148
|
+
raise "error creating pubkey" unless result
|
|
149
149
|
|
|
150
150
|
pubkey = FFI::MemoryPointer.new(:uchar, 65)
|
|
151
151
|
pubkey_len = FFI::MemoryPointer.new(:uint64)
|
|
@@ -157,14 +157,14 @@ module Tapyrus
|
|
|
157
157
|
pubkey_len.put_uint64(0, 65)
|
|
158
158
|
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
|
|
159
159
|
end
|
|
160
|
-
raise
|
|
160
|
+
raise "error serialize pubkey" unless result || pubkey_len.read_uint64 > 0
|
|
161
161
|
pubkey.read_string(pubkey_len.read_uint64).bth
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
def sign_ecdsa(data, privkey, extra_entropy)
|
|
165
165
|
with_context do |context|
|
|
166
166
|
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
|
|
167
|
-
raise
|
|
167
|
+
raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, secret)
|
|
168
168
|
|
|
169
169
|
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
|
|
170
170
|
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
|
@@ -173,7 +173,7 @@ module Tapyrus
|
|
|
173
173
|
ret, tries, max = 0, 0, 20
|
|
174
174
|
|
|
175
175
|
while ret != 1
|
|
176
|
-
raise
|
|
176
|
+
raise "secp256k1_ecdsa_sign failed." if tries >= max
|
|
177
177
|
tries += 1
|
|
178
178
|
ret = secp256k1_ecdsa_sign(context, internal_signature, msg32, secret, nil, entropy)
|
|
179
179
|
end
|
|
@@ -181,7 +181,7 @@ module Tapyrus
|
|
|
181
181
|
signature = FFI::MemoryPointer.new(:uchar, 72)
|
|
182
182
|
signature_len = FFI::MemoryPointer.new(:uint64).put_uint64(0, 72)
|
|
183
183
|
result = secp256k1_ecdsa_signature_serialize_der(context, signature, signature_len, internal_signature)
|
|
184
|
-
raise
|
|
184
|
+
raise "secp256k1_ecdsa_signature_serialize_der failed" unless result
|
|
185
185
|
|
|
186
186
|
signature.read_string(signature_len.read_uint64)
|
|
187
187
|
end
|
|
@@ -190,12 +190,12 @@ module Tapyrus
|
|
|
190
190
|
def sign_schnorr(data, privkey)
|
|
191
191
|
with_context do |context|
|
|
192
192
|
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
|
|
193
|
-
raise
|
|
193
|
+
raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, secret)
|
|
194
194
|
|
|
195
195
|
signature = FFI::MemoryPointer.new(:uchar, 64)
|
|
196
196
|
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
|
197
197
|
unless secp256k1_schnorr_sign(context, signature, msg32, secret, nil, nil) == 1
|
|
198
|
-
raise
|
|
198
|
+
raise "Failed to generate schnorr signature."
|
|
199
199
|
end
|
|
200
200
|
signature.read_string(64)
|
|
201
201
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module Tapyrus
|
|
2
2
|
module Secp256k1
|
|
3
3
|
module RFC6979
|
|
4
|
-
INITIAL_V =
|
|
5
|
-
INITIAL_K =
|
|
6
|
-
ZERO_B =
|
|
7
|
-
ONE_B =
|
|
4
|
+
INITIAL_V = "0101010101010101010101010101010101010101010101010101010101010101".htb
|
|
5
|
+
INITIAL_K = "0000000000000000000000000000000000000000000000000000000000000000".htb
|
|
6
|
+
ZERO_B = "00".htb
|
|
7
|
+
ONE_B = "01".htb
|
|
8
8
|
|
|
9
9
|
module_function
|
|
10
10
|
|
|
@@ -30,16 +30,16 @@ module Tapyrus
|
|
|
30
30
|
v = Tapyrus.hmac_sha256(k, v)
|
|
31
31
|
|
|
32
32
|
# 3.2.h
|
|
33
|
-
t =
|
|
33
|
+
t = ""
|
|
34
34
|
10_000.times do
|
|
35
35
|
v = Tapyrus.hmac_sha256(k, v)
|
|
36
36
|
t = (t + v)
|
|
37
37
|
t_num = t.bth.to_i(16)
|
|
38
38
|
return t_num if 1 <= t_num && t_num < Tapyrus::Secp256k1::GROUP.order
|
|
39
|
-
k = Tapyrus.hmac_sha256(k, v +
|
|
39
|
+
k = Tapyrus.hmac_sha256(k, v + "00".htb)
|
|
40
40
|
v = Tapyrus.hmac_sha256(k, v)
|
|
41
41
|
end
|
|
42
|
-
raise
|
|
42
|
+
raise "A valid nonce was not found."
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -90,7 +90,7 @@ module Tapyrus
|
|
|
90
90
|
def sign_ecdsa(data, privkey, extra_entropy)
|
|
91
91
|
privkey = privkey.htb
|
|
92
92
|
private_key = ECDSA::Format::IntegerOctetString.decode(privkey)
|
|
93
|
-
extra_entropy ||=
|
|
93
|
+
extra_entropy ||= ""
|
|
94
94
|
nonce = RFC6979.generate_rfc6979_nonce(privkey + data, extra_entropy)
|
|
95
95
|
|
|
96
96
|
# port form ecdsa gem.
|
|
@@ -112,7 +112,7 @@ module Tapyrus
|
|
|
112
112
|
|
|
113
113
|
signature = ECDSA::Signature.new(r, s).to_der
|
|
114
114
|
public_key = Tapyrus::Key.new(priv_key: privkey.bth).pubkey
|
|
115
|
-
raise
|
|
115
|
+
raise "Creation of signature failed." unless Tapyrus::Secp256k1::Ruby.verify_sig(data, signature, public_key)
|
|
116
116
|
signature
|
|
117
117
|
end
|
|
118
118
|
|
data/lib/tapyrus/secp256k1.rb
CHANGED
|
@@ -2,8 +2,8 @@ module Tapyrus
|
|
|
2
2
|
module Secp256k1
|
|
3
3
|
GROUP = ECDSA::Group::Secp256k1
|
|
4
4
|
|
|
5
|
-
autoload :Ruby,
|
|
6
|
-
autoload :Native,
|
|
7
|
-
autoload :RFC6979,
|
|
5
|
+
autoload :Ruby, "tapyrus/secp256k1/ruby"
|
|
6
|
+
autoload :Native, "tapyrus/secp256k1/native"
|
|
7
|
+
autoload :RFC6979, "tapyrus/secp256k1/rfc6979"
|
|
8
8
|
end
|
|
9
9
|
end
|
data/lib/tapyrus/slip39/share.rb
CHANGED
|
@@ -16,20 +16,20 @@ module Tapyrus
|
|
|
16
16
|
# @param [Array{String}] words the mnemonic words
|
|
17
17
|
# @return [Tapyrus::SLIP39::Share] a share
|
|
18
18
|
def self.from_words(words)
|
|
19
|
-
raise ArgumentError,
|
|
19
|
+
raise ArgumentError, "Mnemonics should be an array of strings" unless words.is_a?(Array)
|
|
20
20
|
indices =
|
|
21
21
|
words.map do |word|
|
|
22
22
|
index = Tapyrus::SLIP39::WORDS.index(word.downcase)
|
|
23
|
-
raise IndexError,
|
|
23
|
+
raise IndexError, "word not found in words list." unless index
|
|
24
24
|
index
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
raise ArgumentError,
|
|
28
|
-
raise ArgumentError,
|
|
27
|
+
raise ArgumentError, "Invalid mnemonic length." if indices.size < MIN_MNEMONIC_LENGTH_WORDS
|
|
28
|
+
raise ArgumentError, "Invalid mnemonic checksum." unless verify_rs1024_checksum(indices)
|
|
29
29
|
|
|
30
30
|
padding_length = (RADIX_BITS * (indices.size - METADATA_LENGTH_WORDS)) % 16
|
|
31
|
-
raise ArgumentError,
|
|
32
|
-
data = indices.map { |i| i.to_s(2).rjust(10,
|
|
31
|
+
raise ArgumentError, "Invalid mnemonic length." if padding_length > 8
|
|
32
|
+
data = indices.map { |i| i.to_s(2).rjust(10, "0") }.join
|
|
33
33
|
|
|
34
34
|
s = self.new
|
|
35
35
|
s.id = data[0...ID_LENGTH_BITS].to_i(2)
|
|
@@ -47,7 +47,7 @@ module Tapyrus
|
|
|
47
47
|
start_index = 40 + padding_length
|
|
48
48
|
end_index = start_index + value_length - padding_length
|
|
49
49
|
padding_value = data[40...(40 + padding_length)]
|
|
50
|
-
raise ArgumentError,
|
|
50
|
+
raise ArgumentError, "Invalid mnemonic. padding must only zero." unless padding_value.to_i(2) == 0
|
|
51
51
|
s.value = data[start_index...end_index].to_i(2).to_even_length_hex
|
|
52
52
|
s.checksum = data[(40 + value_length)..-1].to_i(2)
|
|
53
53
|
s
|