tapyrus 0.1.0 → 0.2.0
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/README.md +6 -14
- data/exe/tapyrusrbd +2 -2
- data/lib/openassets/util.rb +2 -4
- data/lib/schnorr.rb +83 -0
- data/lib/schnorr/signature.rb +38 -0
- data/lib/tapyrus.rb +9 -11
- data/lib/tapyrus/block.rb +1 -32
- data/lib/tapyrus/block_header.rb +7 -6
- data/lib/tapyrus/chain_params.rb +13 -26
- data/lib/tapyrus/chainparams/{testnet.yml → dev.yml} +7 -9
- data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -10
- data/lib/tapyrus/constants.rb +12 -34
- data/lib/tapyrus/ext.rb +5 -0
- data/lib/tapyrus/ext/json_parser.rb +47 -0
- data/lib/tapyrus/ext_key.rb +5 -10
- data/lib/tapyrus/key.rb +57 -29
- data/lib/tapyrus/message.rb +2 -2
- data/lib/tapyrus/message/base.rb +1 -0
- data/lib/tapyrus/message/block.rb +3 -3
- data/lib/tapyrus/message/cmpct_block.rb +3 -5
- data/lib/tapyrus/message/tx.rb +2 -2
- data/lib/tapyrus/network/peer.rb +1 -15
- data/lib/tapyrus/node/cli.rb +15 -11
- data/lib/tapyrus/node/configuration.rb +1 -1
- data/lib/tapyrus/node/spv.rb +1 -1
- data/lib/tapyrus/opcodes.rb +5 -0
- data/lib/tapyrus/out_point.rb +1 -1
- data/lib/tapyrus/rpc/request_handler.rb +3 -3
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
- data/lib/tapyrus/script/color.rb +79 -0
- data/lib/tapyrus/script/multisig.rb +0 -27
- data/lib/tapyrus/script/script.rb +74 -89
- data/lib/tapyrus/script/script_error.rb +8 -14
- data/lib/tapyrus/script/script_interpreter.rb +65 -86
- data/lib/tapyrus/script/tx_checker.rb +16 -4
- data/lib/tapyrus/secp256k1.rb +1 -0
- data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
- data/lib/tapyrus/secp256k1/ruby.rb +5 -31
- data/lib/tapyrus/store/chain_entry.rb +1 -0
- data/lib/tapyrus/tx.rb +18 -160
- data/lib/tapyrus/tx_in.rb +4 -11
- data/lib/tapyrus/tx_out.rb +2 -1
- data/lib/tapyrus/util.rb +8 -0
- data/lib/tapyrus/validation.rb +1 -6
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +1 -0
- data/lib/tapyrus/wallet/master_key.rb +1 -0
- data/tapyrusrb.gemspec +3 -3
- metadata +42 -39
- data/lib/tapyrus/chainparams/regtest.yml +0 -38
- data/lib/tapyrus/descriptor.rb +0 -147
- data/lib/tapyrus/script_witness.rb +0 -38
@@ -78,24 +78,18 @@ module Tapyrus
|
|
78
78
|
'Witness version reserved for soft-fork upgrades'
|
79
79
|
when SCRIPT_ERR_PUBKEYTYPE
|
80
80
|
'Public key is neither compressed or uncompressed'
|
81
|
-
when SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH
|
82
|
-
'Witness program has incorrect length'
|
83
|
-
when SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY
|
84
|
-
'Witness program was passed an empty witness'
|
85
|
-
when SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH
|
86
|
-
'Witness program hash mismatch'
|
87
|
-
when SCRIPT_ERR_WITNESS_MALLEATED
|
88
|
-
'Witness requires empty scriptSig'
|
89
|
-
when SCRIPT_ERR_WITNESS_MALLEATED_P2SH
|
90
|
-
'Witness requires only-redeemscript scriptSig'
|
91
|
-
when SCRIPT_ERR_WITNESS_UNEXPECTED
|
92
|
-
'Witness provided for non-witness script'
|
93
|
-
when SCRIPT_ERR_WITNESS_PUBKEYTYPE
|
94
|
-
'Using non-compressed keys in segwit'
|
95
81
|
when SCRIPT_ERR_OP_CODESEPARATOR
|
96
82
|
'Using OP_CODESEPARATOR in non-witness scrip'
|
97
83
|
when SCRIPT_ERR_SIG_FINDANDDELETE
|
98
84
|
'Signature is found in scriptCode'
|
85
|
+
when SCRIPT_ERR_OP_COLOR_UNEXPECTED
|
86
|
+
'Unexpected OP_COLOR in script'
|
87
|
+
when SCRIPT_ERR_OP_COLOR_ID_INVALID
|
88
|
+
'Invalid ColorId in script'
|
89
|
+
when SCRIPT_ERR_OP_COLOR_MULTIPLE
|
90
|
+
'Multiple OP_COLOR found in script'
|
91
|
+
when SCRIPT_ERR_OP_COLOR_IN_BRANCH
|
92
|
+
'OP_COLOR is not permitted in a script branch'
|
99
93
|
when SCRIPT_ERR_UNKNOWN_ERROR, SCRIPT_ERR_ERROR_COUNT
|
100
94
|
'unknown error'
|
101
95
|
else
|
@@ -32,32 +32,21 @@ module Tapyrus
|
|
32
32
|
# eval script
|
33
33
|
# @param [Tapyrus::Script] script_sig a signature script (unlock script which data push only)
|
34
34
|
# @param [Tapyrus::Script] script_pubkey a script pubkey (locking script)
|
35
|
-
# @param [Tapyrus::ScriptWitness] witness a witness script
|
36
35
|
# @return [Boolean] result
|
37
|
-
def verify_script(script_sig, script_pubkey
|
36
|
+
def verify_script(script_sig, script_pubkey)
|
38
37
|
|
39
38
|
return set_error(SCRIPT_ERR_SIG_PUSHONLY) if flag?(SCRIPT_VERIFY_SIGPUSHONLY) && !script_sig.push_only?
|
40
39
|
|
41
40
|
stack_copy = nil
|
42
|
-
had_witness = false
|
43
41
|
|
44
|
-
return false unless eval_script(script_sig, :base)
|
42
|
+
return false unless eval_script(script_sig, :base, false)
|
45
43
|
|
46
44
|
stack_copy = stack.dup if flag?(SCRIPT_VERIFY_P2SH)
|
47
45
|
|
48
|
-
return false unless eval_script(script_pubkey, :base)
|
46
|
+
return false unless eval_script(script_pubkey, :base, false)
|
49
47
|
|
50
48
|
return set_error(SCRIPT_ERR_EVAL_FALSE) if stack.empty? || !cast_to_bool(stack.last.htb)
|
51
49
|
|
52
|
-
# Bare witness programs
|
53
|
-
if flag?(SCRIPT_VERIFY_WITNESS) && script_pubkey.witness_program?
|
54
|
-
had_witness = true
|
55
|
-
return set_error(SCRIPT_ERR_WITNESS_MALLEATED) unless script_sig.size == 0
|
56
|
-
version, program = script_pubkey.witness_data
|
57
|
-
stack_copy = stack.dup
|
58
|
-
return false unless verify_witness_program(witness, version, program)
|
59
|
-
end
|
60
|
-
|
61
50
|
# Additional validation for spend-to-script-hash transactions
|
62
51
|
if flag?(SCRIPT_VERIFY_P2SH) && script_pubkey.p2sh?
|
63
52
|
return set_error(SCRIPT_ERR_SIG_PUSHONLY) unless script_sig.push_only?
|
@@ -69,18 +58,8 @@ module Tapyrus
|
|
69
58
|
rescue Exception => e
|
70
59
|
return set_error(SCRIPT_ERR_BAD_OPCODE, "Failed to parse serialized redeem script for P2SH. #{e.message}")
|
71
60
|
end
|
72
|
-
return false unless eval_script(redeem_script, :base)
|
61
|
+
return false unless eval_script(redeem_script, :base, true)
|
73
62
|
return set_error(SCRIPT_ERR_EVAL_FALSE) if stack.empty? || !cast_to_bool(stack.last)
|
74
|
-
|
75
|
-
# P2SH witness program
|
76
|
-
if flag?(SCRIPT_VERIFY_WITNESS) && redeem_script.witness_program?
|
77
|
-
had_witness = true
|
78
|
-
# The scriptSig must be _exactly_ a single push of the redeemScript. Otherwise we reintroduce malleability.
|
79
|
-
return set_error(SCRIPT_ERR_WITNESS_MALLEATED_P2SH) unless script_sig == (Tapyrus::Script.new << redeem_script.to_payload.bth)
|
80
|
-
|
81
|
-
version, program = redeem_script.witness_data
|
82
|
-
return false unless verify_witness_program(witness, version, program)
|
83
|
-
end
|
84
63
|
end
|
85
64
|
|
86
65
|
# The CLEANSTACK check is only performed after potential P2SH evaluation,
|
@@ -93,11 +72,6 @@ module Tapyrus
|
|
93
72
|
return set_error(SCRIPT_ERR_CLEANSTACK) unless stack.size == 1
|
94
73
|
end
|
95
74
|
|
96
|
-
if flag?(SCRIPT_VERIFY_WITNESS)
|
97
|
-
raise 'assert' unless flag?(SCRIPT_VERIFY_P2SH)
|
98
|
-
return set_error(SCRIPT_ERR_WITNESS_UNEXPECTED) if !had_witness && !witness.empty?
|
99
|
-
end
|
100
|
-
|
101
75
|
true
|
102
76
|
end
|
103
77
|
|
@@ -106,45 +80,14 @@ module Tapyrus
|
|
106
80
|
false
|
107
81
|
end
|
108
82
|
|
109
|
-
def
|
110
|
-
if version == 0
|
111
|
-
if program.bytesize == 32
|
112
|
-
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY) if witness.stack.size == 0
|
113
|
-
script_pubkey = Tapyrus::Script.parse_from_payload(witness.stack.last)
|
114
|
-
@stack = witness.stack[0..-2].map{|w|w.bth}
|
115
|
-
script_hash = Tapyrus.sha256(script_pubkey.to_payload)
|
116
|
-
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH) unless script_hash == program
|
117
|
-
elsif program.bytesize == 20
|
118
|
-
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH) unless witness.stack.size == 2
|
119
|
-
script_pubkey = Tapyrus::Script.to_p2pkh(program.bth)
|
120
|
-
@stack = witness.stack.map{|w|w.bth}
|
121
|
-
else
|
122
|
-
return set_error(SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH)
|
123
|
-
end
|
124
|
-
elsif flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
125
|
-
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
126
|
-
else
|
127
|
-
return true # Higher version witness scripts return true for future softfork compatibility
|
128
|
-
end
|
129
|
-
|
130
|
-
stack.each do |s| # Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
|
131
|
-
return set_error(SCRIPT_ERR_PUSH_SIZE) if s.htb.bytesize > MAX_SCRIPT_ELEMENT_SIZE
|
132
|
-
end
|
133
|
-
|
134
|
-
return false unless eval_script(script_pubkey, :witness_v0)
|
135
|
-
|
136
|
-
return set_error(SCRIPT_ERR_EVAL_FALSE) unless stack.size == 1
|
137
|
-
return set_error(SCRIPT_ERR_EVAL_FALSE) unless cast_to_bool(stack.last)
|
138
|
-
true
|
139
|
-
end
|
140
|
-
|
141
|
-
def eval_script(script, sig_version)
|
83
|
+
def eval_script(script, sig_version, is_redeem_script)
|
142
84
|
return set_error(SCRIPT_ERR_SCRIPT_SIZE) if script.size > MAX_SCRIPT_SIZE
|
143
85
|
begin
|
144
86
|
flow_stack = []
|
145
87
|
alt_stack = []
|
146
88
|
last_code_separator_index = 0
|
147
89
|
op_count = 0
|
90
|
+
color_id = nil
|
148
91
|
|
149
92
|
script.chunks.each_with_index do |c, index|
|
150
93
|
need_exec = !flow_stack.include?(false)
|
@@ -209,7 +152,7 @@ module Tapyrus
|
|
209
152
|
if need_exec
|
210
153
|
return set_error(SCRIPT_ERR_UNBALANCED_CONDITIONAL) if stack.size < 1
|
211
154
|
value = pop_string.htb
|
212
|
-
if
|
155
|
+
if flag?(SCRIPT_VERIFY_MINIMALIF)
|
213
156
|
if value.bytesize > 1 || (value.bytesize == 1 && value[0].unpack('C').first != 1)
|
214
157
|
return set_error(SCRIPT_ERR_MINIMALIF)
|
215
158
|
end
|
@@ -409,8 +352,8 @@ module Tapyrus
|
|
409
352
|
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE) if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
410
353
|
subscript = tmp
|
411
354
|
end
|
412
|
-
|
413
|
-
|
355
|
+
return false if (sig.htb.bytesize == Tapyrus::Key::COMPACT_SIGNATURE_SIZE ?
|
356
|
+
!check_schnorr_signature_encoding(sig) : !check_ecdsa_signature_encoding(sig)) || !check_pubkey_encoding(pubkey)
|
414
357
|
|
415
358
|
success = checker.check_sig(sig, pubkey, subscript, sig_version)
|
416
359
|
|
@@ -428,6 +371,19 @@ module Tapyrus
|
|
428
371
|
return set_error(SCRIPT_ERR_CHECKSIGVERIFY)
|
429
372
|
end
|
430
373
|
end
|
374
|
+
when OP_CHECKDATASIG, OP_CHECKDATASIGVERIFY
|
375
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 3
|
376
|
+
sig, msg, pubkey = pop_string(3)
|
377
|
+
# check signature encoding without hashtype byte
|
378
|
+
return false if (sig.htb.bytesize != (Tapyrus::Key::COMPACT_SIGNATURE_SIZE - 1) && !check_ecdsa_signature_encoding(sig, true)) || !check_pubkey_encoding(pubkey)
|
379
|
+
digest = Tapyrus.sha256(msg)
|
380
|
+
success = checker.verify_sig(sig, pubkey, digest)
|
381
|
+
return set_error(SCRIPT_ERR_SIG_NULLFAIL) if !success && flag?(SCRIPT_VERIFY_NULLFAIL) && sig.bytesize > 0
|
382
|
+
push_int(success ? 1 : 0)
|
383
|
+
if opcode == OP_CHECKDATASIGVERIFY
|
384
|
+
stack.pop if success
|
385
|
+
return set_error(SCRIPT_ERR_CHECKDATASIGVERIFY) unless success
|
386
|
+
end
|
431
387
|
when OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY
|
432
388
|
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
433
389
|
pubkey_count = pop_int
|
@@ -463,10 +419,17 @@ module Tapyrus
|
|
463
419
|
end
|
464
420
|
|
465
421
|
success = true
|
422
|
+
current_sig_scheme = nil
|
466
423
|
while success && sig_count > 0
|
467
424
|
sig = sigs.pop
|
468
425
|
pubkey = pubkeys.pop
|
469
|
-
|
426
|
+
sig_scheme = sig.htb.bytesize == Tapyrus::Key::COMPACT_SIGNATURE_SIZE ? :schnorr : :ecdsa
|
427
|
+
current_sig_scheme = sig_scheme if current_sig_scheme.nil?
|
428
|
+
|
429
|
+
return false if (sig_scheme == :schnorr ? !check_schnorr_signature_encoding(sig) : !check_ecdsa_signature_encoding(sig)) || !check_pubkey_encoding(pubkey) # error already set.
|
430
|
+
|
431
|
+
return set_error(SCRIPT_ERR_MIXED_SCHEME_MULTISIG) unless sig_scheme == current_sig_scheme
|
432
|
+
|
470
433
|
ok = checker.check_sig(sig, pubkey, subscript, sig_version)
|
471
434
|
if ok
|
472
435
|
sig_count -= 1
|
@@ -488,9 +451,8 @@ module Tapyrus
|
|
488
451
|
# Unfortunately this is a potential source of mutability,
|
489
452
|
# so optionally verify it is exactly equal to zero prior to removing it from the stack.
|
490
453
|
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
491
|
-
|
492
|
-
|
493
|
-
end
|
454
|
+
return set_error(SCRIPT_ERR_SIG_NULLDUMMY) if stack[-1].size > 0
|
455
|
+
|
494
456
|
stack.pop
|
495
457
|
|
496
458
|
push_int(success ? 1 : 0)
|
@@ -503,6 +465,25 @@ module Tapyrus
|
|
503
465
|
end
|
504
466
|
when OP_RETURN
|
505
467
|
return set_error(SCRIPT_ERR_OP_RETURN)
|
468
|
+
when OP_COLOR
|
469
|
+
# Color id is not permitted in p2sh redeem script
|
470
|
+
return set_error(SCRIPT_ERR_OP_COLOR_UNEXPECTED) if is_redeem_script
|
471
|
+
|
472
|
+
# if Color id is already initialized this must be an extra
|
473
|
+
return set_error(SCRIPT_ERR_OP_COLOR_MULTIPLE) if color_id && color_id.type != Tapyrus::Color::TokenTypes::NONE
|
474
|
+
|
475
|
+
# color id is not allowed inside OP_IF
|
476
|
+
return set_error(SCRIPT_ERR_OP_COLOR_IN_BRANCH) unless flow_stack.empty?
|
477
|
+
|
478
|
+
# pop one stack element and verify that it exists
|
479
|
+
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size() < 1
|
480
|
+
|
481
|
+
color_id = Tapyrus::Color::ColorIdentifier.parse_from_payload(stack.last.htb)
|
482
|
+
|
483
|
+
# check ColorIdentifier is valid
|
484
|
+
return set_error(SCRIPT_ERR_OP_COLOR_ID_INVALID) unless color_id.valid?
|
485
|
+
|
486
|
+
stack.pop
|
506
487
|
else
|
507
488
|
return set_error(SCRIPT_ERR_BAD_OPCODE)
|
508
489
|
end
|
@@ -586,20 +567,26 @@ module Tapyrus
|
|
586
567
|
end
|
587
568
|
end
|
588
569
|
|
589
|
-
def
|
570
|
+
def check_ecdsa_signature_encoding(sig, data_sig = false)
|
590
571
|
return true if sig.size.zero?
|
591
|
-
if
|
572
|
+
if !Key.valid_signature_encoding?(sig.htb, data_sig)
|
592
573
|
return set_error(SCRIPT_ERR_SIG_DER)
|
593
|
-
elsif
|
574
|
+
elsif !low_der_signature?(sig, data_sig)
|
594
575
|
return false
|
595
|
-
elsif
|
576
|
+
elsif !data_sig && !defined_hashtype_signature?(sig)
|
596
577
|
return set_error(SCRIPT_ERR_SIG_HASHTYPE)
|
597
578
|
end
|
598
579
|
true
|
599
580
|
end
|
600
581
|
|
601
|
-
def
|
602
|
-
return
|
582
|
+
def check_schnorr_signature_encoding(sig, data_sig = false)
|
583
|
+
return false unless sig.htb.bytesize == (data_sig ? 64 : 65)
|
584
|
+
return set_error(SCRIPT_ERR_SIG_HASHTYPE) if !data_sig && !defined_hashtype_signature?(sig)
|
585
|
+
true
|
586
|
+
end
|
587
|
+
|
588
|
+
def low_der_signature?(sig, data_sig = false)
|
589
|
+
return set_error(SCRIPT_ERR_SIG_DER) unless Key.valid_signature_encoding?(sig.htb, data_sig)
|
603
590
|
return set_error(SCRIPT_ERR_SIG_HIGH_S) unless Key.low_signature?(sig.htb)
|
604
591
|
true
|
605
592
|
end
|
@@ -609,20 +596,12 @@ module Tapyrus
|
|
609
596
|
return false if sig.empty?
|
610
597
|
s = sig.unpack('C*')
|
611
598
|
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
|
612
|
-
hash_type &= (~(Tapyrus::SIGHASH_FORK_ID)) if Tapyrus.chain_params.fork_chain? # for fork coin.
|
613
599
|
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single]
|
614
600
|
true
|
615
601
|
end
|
616
602
|
|
617
|
-
def check_pubkey_encoding(pubkey
|
618
|
-
|
619
|
-
return set_error(SCRIPT_ERR_PUBKEYTYPE)
|
620
|
-
end
|
621
|
-
# Only compressed keys are accepted in segwit
|
622
|
-
if flag?(SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) &&
|
623
|
-
sig_version == :witness_v0 && !Key.compress_pubkey?(pubkey)
|
624
|
-
return set_error(SCRIPT_ERR_WITNESS_PUBKEYTYPE)
|
625
|
-
end
|
603
|
+
def check_pubkey_encoding(pubkey)
|
604
|
+
return set_error(SCRIPT_ERR_PUBKEYTYPE) unless Key.compress_or_uncompress_pubkey?(pubkey)
|
626
605
|
true
|
627
606
|
end
|
628
607
|
|
@@ -12,10 +12,11 @@ module Tapyrus
|
|
12
12
|
end
|
13
13
|
|
14
14
|
# check signature
|
15
|
-
# @param [String] script_sig
|
16
|
-
# @param [String] pubkey
|
15
|
+
# @param [String] script_sig a signature with hex format.
|
16
|
+
# @param [String] pubkey a public key with hex format.
|
17
17
|
# @param [Tapyrus::Script] script_code
|
18
18
|
# @param [Integer] sig_version
|
19
|
+
# @return [Boolean] if check is passed return true, otherwise false.
|
19
20
|
def check_sig(script_sig, pubkey, script_code, sig_version)
|
20
21
|
return false if script_sig.empty?
|
21
22
|
script_sig = script_sig.htb
|
@@ -23,9 +24,20 @@ module Tapyrus
|
|
23
24
|
sig = script_sig[0..-2]
|
24
25
|
sighash = tx.sighash_for_input(input_index, script_code, hash_type: hash_type,
|
25
26
|
amount: amount, sig_version: sig_version)
|
27
|
+
verify_sig(sig.bth, pubkey, sighash)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Check data signature.
|
31
|
+
# @param [String] sig a signature with hex format.
|
32
|
+
# @param [String] pubkey a public key with hex format.
|
33
|
+
# @param [String] digest a message digest with binary format to be verified.
|
34
|
+
# @return [Boolean] if check is passed return true, otherwise false.
|
35
|
+
def verify_sig(sig, pubkey, digest)
|
26
36
|
key_type = pubkey.start_with?('02') || pubkey.start_with?('03') ? Key::TYPES[:compressed] : Key::TYPES[:uncompressed]
|
37
|
+
sig = sig.htb
|
38
|
+
algo = sig.bytesize == 64 ? :schnorr : :ecdsa
|
27
39
|
key = Key.new(pubkey: pubkey, key_type: key_type)
|
28
|
-
key.verify(sig,
|
40
|
+
key.verify(sig, digest, algo: algo)
|
29
41
|
end
|
30
42
|
|
31
43
|
def check_locktime(locktime)
|
@@ -53,7 +65,7 @@ module Tapyrus
|
|
53
65
|
def check_sequence(sequence)
|
54
66
|
tx_sequence = tx.inputs[input_index].sequence
|
55
67
|
# Fail if the transaction's version number is not set high enough to trigger BIP 68 rules.
|
56
|
-
return false if tx.
|
68
|
+
return false if tx.features < 2
|
57
69
|
|
58
70
|
# Sequence numbers with their most significant bit set are not consensus constrained.
|
59
71
|
# Testing that the transaction's sequence number do not have this bit set prevents using this property to get around a CHECKSEQUENCEVERIFY check.
|
data/lib/tapyrus/secp256k1.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
module Secp256k1
|
3
|
+
module RFC6979
|
4
|
+
|
5
|
+
INITIAL_V = '0101010101010101010101010101010101010101010101010101010101010101'.htb
|
6
|
+
INITIAL_K = '0000000000000000000000000000000000000000000000000000000000000000'.htb
|
7
|
+
ZERO_B = '00'.htb
|
8
|
+
ONE_B = '01'.htb
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
# generate temporary key k to be used when ECDSA sign.
|
13
|
+
# https://tools.ietf.org/html/rfc6979#section-3.2
|
14
|
+
# @param [String] key_data a data contains private key and message.
|
15
|
+
# @param [String] extra_entropy extra entropy with binary format.
|
16
|
+
# @return [Integer] a nonce.
|
17
|
+
def generate_rfc6979_nonce(key_data, extra_entropy)
|
18
|
+
v = INITIAL_V # 3.2.b
|
19
|
+
k = INITIAL_K # 3.2.c
|
20
|
+
# 3.2.d
|
21
|
+
k = Tapyrus.hmac_sha256(k, v + ZERO_B + key_data + extra_entropy)
|
22
|
+
# 3.2.e
|
23
|
+
v = Tapyrus.hmac_sha256(k, v)
|
24
|
+
# 3.2.f
|
25
|
+
k = Tapyrus.hmac_sha256(k, v + ONE_B + key_data + extra_entropy)
|
26
|
+
# 3.2.g
|
27
|
+
v = Tapyrus.hmac_sha256(k, v)
|
28
|
+
# 3.2.h
|
29
|
+
t = ''
|
30
|
+
10000.times do
|
31
|
+
v = Tapyrus.hmac_sha256(k, v)
|
32
|
+
t = (t + v)
|
33
|
+
t_num = t.bth.to_i(16)
|
34
|
+
return t_num if 1 <= t_num && t_num < Tapyrus::Secp256k1::GROUP.order
|
35
|
+
k = Tapyrus.hmac_sha256(k, v + '00'.htb)
|
36
|
+
v = Tapyrus.hmac_sha256(k, v)
|
37
|
+
end
|
38
|
+
raise 'A valid nonce was not found.'
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -35,7 +35,7 @@ module Tapyrus
|
|
35
35
|
privkey = privkey.htb
|
36
36
|
private_key = ECDSA::Format::IntegerOctetString.decode(privkey)
|
37
37
|
extra_entropy ||= ''
|
38
|
-
nonce = generate_rfc6979_nonce(data,
|
38
|
+
nonce = RFC6979.generate_rfc6979_nonce(privkey + data, extra_entropy)
|
39
39
|
|
40
40
|
# port form ecdsa gem.
|
41
41
|
r_point = GROUP.new_point(nonce)
|
@@ -74,6 +74,10 @@ module Tapyrus
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
alias :valid_sig? :verify_sig
|
78
|
+
|
79
|
+
module_function :valid_sig?
|
80
|
+
|
77
81
|
# if +pubkey+ is hybrid public key format, it convert uncompressed format.
|
78
82
|
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2012-June/001578.html
|
79
83
|
def repack_pubkey(pubkey)
|
@@ -87,36 +91,6 @@ module Tapyrus
|
|
87
91
|
end
|
88
92
|
end
|
89
93
|
|
90
|
-
INITIAL_V = '0101010101010101010101010101010101010101010101010101010101010101'.htb
|
91
|
-
INITIAL_K = '0000000000000000000000000000000000000000000000000000000000000000'.htb
|
92
|
-
ZERO_B = '00'.htb
|
93
|
-
ONE_B = '01'.htb
|
94
|
-
|
95
|
-
# generate temporary key k to be used when ECDSA sign.
|
96
|
-
# https://tools.ietf.org/html/rfc6979#section-3.2
|
97
|
-
def generate_rfc6979_nonce(data, privkey, extra_entropy)
|
98
|
-
v = INITIAL_V # 3.2.b
|
99
|
-
k = INITIAL_K # 3.2.c
|
100
|
-
# 3.2.d
|
101
|
-
k = Tapyrus.hmac_sha256(k, v + ZERO_B + privkey + data + extra_entropy)
|
102
|
-
# 3.2.e
|
103
|
-
v = Tapyrus.hmac_sha256(k, v)
|
104
|
-
# 3.2.f
|
105
|
-
k = Tapyrus.hmac_sha256(k, v + ONE_B + privkey + data + extra_entropy)
|
106
|
-
# 3.2.g
|
107
|
-
v = Tapyrus.hmac_sha256(k, v)
|
108
|
-
# 3.2.h
|
109
|
-
t = ''
|
110
|
-
10000.times do
|
111
|
-
v = Tapyrus.hmac_sha256(k, v)
|
112
|
-
t = (t + v)
|
113
|
-
t_num = t.bth.to_i(16)
|
114
|
-
return t_num if 1 <= t_num && t_num < GROUP.order
|
115
|
-
k = Tapyrus.hmac_sha256(k, v + '00'.htb)
|
116
|
-
v = Tapyrus.hmac_sha256(k, v)
|
117
|
-
end
|
118
|
-
raise 'A valid nonce was not found.'
|
119
|
-
end
|
120
94
|
end
|
121
95
|
|
122
96
|
end
|