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
@@ -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
|