monacoin-ruby 0.1.2 → 0.1.3
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/lib/bitcoin.rb +933 -0
- data/lib/bitcoin/bloom_filter.rb +125 -0
- data/lib/bitcoin/builder.rb +494 -0
- data/lib/bitcoin/connection.rb +130 -0
- data/lib/bitcoin/contracthash.rb +76 -0
- data/lib/bitcoin/dogecoin.rb +97 -0
- data/lib/bitcoin/electrum/mnemonic.rb +162 -0
- data/lib/bitcoin/ext_key.rb +191 -0
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +75 -0
- data/lib/bitcoin/ffi/openssl.rb +388 -0
- data/lib/bitcoin/ffi/secp256k1.rb +266 -0
- data/lib/bitcoin/key.rb +280 -0
- data/lib/bitcoin/litecoin.rb +83 -0
- data/lib/bitcoin/logger.rb +86 -0
- data/lib/bitcoin/protocol.rb +189 -0
- data/lib/bitcoin/protocol/address.rb +50 -0
- data/lib/bitcoin/protocol/alert.rb +46 -0
- data/lib/bitcoin/protocol/aux_pow.rb +123 -0
- data/lib/bitcoin/protocol/block.rb +285 -0
- data/lib/bitcoin/protocol/handler.rb +43 -0
- data/lib/bitcoin/protocol/parser.rb +194 -0
- data/lib/bitcoin/protocol/partial_merkle_tree.rb +61 -0
- data/lib/bitcoin/protocol/reject.rb +38 -0
- data/lib/bitcoin/protocol/script_witness.rb +31 -0
- data/lib/bitcoin/protocol/tx.rb +587 -0
- data/lib/bitcoin/protocol/txin.rb +142 -0
- data/lib/bitcoin/protocol/txout.rb +95 -0
- data/lib/bitcoin/protocol/version.rb +88 -0
- data/lib/bitcoin/script.rb +1656 -0
- data/lib/bitcoin/trezor/mnemonic.rb +130 -0
- data/lib/bitcoin/version.rb +3 -0
- metadata +32 -1
@@ -0,0 +1,142 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
module Bitcoin
|
4
|
+
module Protocol
|
5
|
+
|
6
|
+
class TxIn
|
7
|
+
|
8
|
+
# previous output hash
|
9
|
+
attr_accessor :prev_out_hash
|
10
|
+
alias :prev_out :prev_out_hash
|
11
|
+
def prev_out=(hash); @prev_out_hash = hash; end
|
12
|
+
|
13
|
+
# previous output index
|
14
|
+
attr_accessor :prev_out_index
|
15
|
+
|
16
|
+
# script_sig input Script (signature)
|
17
|
+
attr_accessor :script_sig, :script_sig_length
|
18
|
+
|
19
|
+
# signature hash and the address of the key that needs to sign it
|
20
|
+
# (used when dealing with unsigned or partly signed tx)
|
21
|
+
attr_accessor :sig_hash, :sig_address
|
22
|
+
|
23
|
+
# segregated witness
|
24
|
+
attr_accessor :script_witness
|
25
|
+
|
26
|
+
alias :script :script_sig
|
27
|
+
alias :script_length :script_sig_length
|
28
|
+
|
29
|
+
# sequence
|
30
|
+
attr_accessor :sequence
|
31
|
+
|
32
|
+
DEFAULT_SEQUENCE = "\xff\xff\xff\xff"
|
33
|
+
NULL_HASH = "\x00"*32
|
34
|
+
COINBASE_INDEX = 0xffffffff
|
35
|
+
|
36
|
+
def initialize *args
|
37
|
+
@prev_out_hash, @prev_out_index, @script_sig_length,
|
38
|
+
@script_sig, @sequence = *args
|
39
|
+
@script_sig_length ||= 0
|
40
|
+
@script_sig ||= ''
|
41
|
+
@sequence ||= DEFAULT_SEQUENCE
|
42
|
+
@script_witness = ScriptWitness.new
|
43
|
+
end
|
44
|
+
|
45
|
+
# compare to another txout
|
46
|
+
def ==(other)
|
47
|
+
@prev_out_hash == other.prev_out_hash &&
|
48
|
+
@prev_out_index == other.prev_out_index &&
|
49
|
+
@script_sig == other.script_sig &&
|
50
|
+
@sequence == other.sequence
|
51
|
+
rescue
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
# returns true if the sequence number is final (DEFAULT_SEQUENCE)
|
56
|
+
def is_final?
|
57
|
+
self.sequence == DEFAULT_SEQUENCE
|
58
|
+
end
|
59
|
+
|
60
|
+
# parse raw binary data for transaction input
|
61
|
+
def parse_data(data)
|
62
|
+
buf = data.is_a?(String) ? StringIO.new(data) : data
|
63
|
+
parse_data_from_io(buf)
|
64
|
+
buf.pos
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.from_io(buf)
|
68
|
+
txin = new; txin.parse_data_from_io(buf); txin
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_data_from_io(buf)
|
72
|
+
@prev_out_hash, @prev_out_index = buf.read(36).unpack("a32V")
|
73
|
+
@script_sig_length = Protocol.unpack_var_int_from_io(buf)
|
74
|
+
@script_sig = buf.read(@script_sig_length)
|
75
|
+
@sequence = buf.read(4)
|
76
|
+
end
|
77
|
+
|
78
|
+
def parsed_script
|
79
|
+
@parsed_script ||= Bitcoin::Script.new(script_sig)
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_payload(script=@script_sig, sequence=@sequence)
|
83
|
+
[@prev_out_hash, @prev_out_index].pack("a32V") << Protocol.pack_var_int(script.bytesize) << script << (sequence || DEFAULT_SEQUENCE)
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_hash(options = {})
|
87
|
+
t = { 'prev_out' => { 'hash' => @prev_out_hash.reverse_hth, 'n' => @prev_out_index } }
|
88
|
+
if coinbase?
|
89
|
+
t['coinbase'] = @script_sig.unpack("H*")[0]
|
90
|
+
else # coinbase tx
|
91
|
+
t['scriptSig'] = Bitcoin::Script.new(@script_sig).to_string
|
92
|
+
end
|
93
|
+
t['sequence'] = @sequence.unpack("V")[0] unless @sequence == "\xff\xff\xff\xff"
|
94
|
+
t['witness'] = @script_witness.stack.map{|s|s.bth} unless @script_witness.empty?
|
95
|
+
t
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.from_hash(input)
|
99
|
+
previous_hash = input['previous_transaction_hash'] || input['prev_out']['hash']
|
100
|
+
previous_output_index = input['output_index'] || input['prev_out']['n']
|
101
|
+
txin = TxIn.new([ previous_hash ].pack('H*').reverse, previous_output_index)
|
102
|
+
if input['coinbase']
|
103
|
+
txin.script_sig = [ input['coinbase'] ].pack("H*")
|
104
|
+
else
|
105
|
+
txin.script_sig = Script.binary_from_string(input['scriptSig'] || input['script'])
|
106
|
+
end
|
107
|
+
if input['witness']
|
108
|
+
input['witness'].each {|w| txin.script_witness.stack << w.htb}
|
109
|
+
end
|
110
|
+
txin.sequence = [ input['sequence'] || 0xffffffff ].pack("V")
|
111
|
+
txin
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.from_hex_hash(hash, index)
|
115
|
+
TxIn.new([hash].pack("H*").reverse, index, 0)
|
116
|
+
end
|
117
|
+
|
118
|
+
# previous output in hex
|
119
|
+
def previous_output
|
120
|
+
@prev_out_hash.reverse_hth
|
121
|
+
end
|
122
|
+
|
123
|
+
# check if input is coinbase
|
124
|
+
def coinbase?
|
125
|
+
(@prev_out_index == COINBASE_INDEX) && (@prev_out_hash == NULL_HASH)
|
126
|
+
end
|
127
|
+
|
128
|
+
# set script_sig and script_sig_length
|
129
|
+
def script_sig=(script_sig)
|
130
|
+
@script_sig_length = script_sig.bytesize
|
131
|
+
@script_sig = script_sig
|
132
|
+
end
|
133
|
+
alias :script= :script_sig=
|
134
|
+
|
135
|
+
def add_signature_pubkey_script(sig, pubkey_hex)
|
136
|
+
self.script = Bitcoin::Script.to_signature_pubkey_script(sig, [pubkey_hex].pack("H*"))
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
module Bitcoin
|
4
|
+
module Protocol
|
5
|
+
|
6
|
+
class TxOut
|
7
|
+
|
8
|
+
# output value (in base units; "satoshi")
|
9
|
+
attr_accessor :value
|
10
|
+
|
11
|
+
# pk_script output Script
|
12
|
+
attr_accessor :pk_script, :pk_script_length
|
13
|
+
|
14
|
+
# p2sh redeem script (optional, not included in the serialized binary format)
|
15
|
+
attr_accessor :redeem_script
|
16
|
+
|
17
|
+
def initialize *args
|
18
|
+
if args.size == 2
|
19
|
+
@value, @pk_script_length, @pk_script = args[0], args[1].bytesize, args[1]
|
20
|
+
else
|
21
|
+
@value, @pk_script_length, @pk_script = *args
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(other)
|
26
|
+
@value == other.value && @pk_script == other.pk_script rescue false
|
27
|
+
end
|
28
|
+
|
29
|
+
# parse raw binary data for transaction output
|
30
|
+
def parse_data(data)
|
31
|
+
buf = data.is_a?(String) ? StringIO.new(data) : data
|
32
|
+
parse_data_from_io(buf)
|
33
|
+
buf.pos
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_io(buf)
|
37
|
+
txout = new; txout.parse_data_from_io(buf); txout
|
38
|
+
end
|
39
|
+
|
40
|
+
# parse raw binary data for transaction output
|
41
|
+
def parse_data_from_io(buf)
|
42
|
+
@value = buf.read(8).unpack("Q")[0]
|
43
|
+
@pk_script_length = Protocol.unpack_var_int_from_io(buf)
|
44
|
+
@pk_script = buf.read(@pk_script_length)
|
45
|
+
end
|
46
|
+
|
47
|
+
alias :parse_payload :parse_data
|
48
|
+
|
49
|
+
def parsed_script
|
50
|
+
@parsed_script ||= Bitcoin::Script.new(pk_script)
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_payload
|
54
|
+
[@value].pack("Q") << Protocol.pack_var_int(@pk_script_length) << @pk_script
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_null_payload
|
58
|
+
self.class.new(-1, '').to_payload
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_hash(options = {})
|
62
|
+
h = { 'value' => "%.8f" % (@value / 100000000.0),
|
63
|
+
'scriptPubKey' => parsed_script.to_string }
|
64
|
+
h["address"] = parsed_script.get_address if parsed_script.is_hash160? && options[:with_address]
|
65
|
+
h
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.from_hash(output)
|
69
|
+
amount = output['value'] ? output['value'].gsub('.','').to_i : output['amount']
|
70
|
+
script = Script.binary_from_string(output['scriptPubKey'] || output['script'])
|
71
|
+
new(amount, script)
|
72
|
+
end
|
73
|
+
|
74
|
+
# set pk_script and pk_script_length
|
75
|
+
def pk_script=(pk_script)
|
76
|
+
@pk_script_length, @pk_script = pk_script.bytesize, pk_script
|
77
|
+
end
|
78
|
+
|
79
|
+
alias :amount :value
|
80
|
+
alias :amount= :value=
|
81
|
+
|
82
|
+
alias :script :pk_script
|
83
|
+
alias :script= :pk_script=
|
84
|
+
|
85
|
+
# create output spending +value+ btc (base units) to +address+
|
86
|
+
def self.value_to_address(value, address)
|
87
|
+
pk_script = Bitcoin::Script.to_address_script(address)
|
88
|
+
raise "Script#pk_script nil with address #{address}" unless pk_script
|
89
|
+
new(value, pk_script)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
module Bitcoin
|
4
|
+
module Protocol
|
5
|
+
|
6
|
+
# https://en.bitcoin.it/wiki/Protocol_specification#version
|
7
|
+
class Version
|
8
|
+
# services bit constants
|
9
|
+
NODE_NONE = 0
|
10
|
+
NODE_NETWORK = (1 << 0)
|
11
|
+
|
12
|
+
attr_reader :fields
|
13
|
+
|
14
|
+
def initialize(opts={})
|
15
|
+
@fields = {
|
16
|
+
:version => Bitcoin.network[:protocol_version],
|
17
|
+
:services => NODE_NETWORK,
|
18
|
+
:time => Time.now.tv_sec,
|
19
|
+
:from => "127.0.0.1:8333",
|
20
|
+
:to => "127.0.0.1:8333",
|
21
|
+
:nonce => Bitcoin::Protocol::Uniq,
|
22
|
+
:user_agent => "/bitcoin-ruby:#{Bitcoin::VERSION}/",
|
23
|
+
:last_block => 0, # 188617
|
24
|
+
:relay => true # BIP0037
|
25
|
+
}.merge( opts.reject{|k,v| v == nil } )
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_payload
|
29
|
+
[
|
30
|
+
@fields.values_at(:version, :services, :time).pack("VQQ"),
|
31
|
+
pack_address_field(@fields[:from]),
|
32
|
+
pack_address_field(@fields[:to]),
|
33
|
+
@fields.values_at(:nonce).pack("Q"),
|
34
|
+
Protocol.pack_var_string(@fields[:user_agent]),
|
35
|
+
@fields.values_at(:last_block).pack("V"),
|
36
|
+
Protocol.pack_boolean(@fields[:relay]) # Satoshi 0.8.6 doesn't send this but it does respect it
|
37
|
+
].join
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_pkt
|
41
|
+
Bitcoin::Protocol.pkt("version", to_payload)
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse(payload)
|
45
|
+
version, services, timestamp, to, from, nonce, payload = payload.unpack("VQQa26a26Qa*")
|
46
|
+
to, from = unpack_address_field(to), unpack_address_field(from)
|
47
|
+
user_agent, payload = Protocol.unpack_var_string(payload)
|
48
|
+
last_block, payload = payload.unpack("Va*")
|
49
|
+
relay, payload = unpack_relay_field(version, payload)
|
50
|
+
|
51
|
+
@fields = {
|
52
|
+
:version => version, :services => services, :time => timestamp,
|
53
|
+
:from => from, :to => to, :nonce => nonce,
|
54
|
+
:user_agent => user_agent.to_s, :last_block => last_block, :relay => relay
|
55
|
+
}
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def unpack_address_field(payload)
|
60
|
+
ip, port = payload.unpack("x8x12a4n")
|
61
|
+
"#{ip.unpack("C*").join(".")}:#{port}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def pack_address_field(addr_str)
|
65
|
+
host, port = addr_str.split(":")
|
66
|
+
port = port ? port.to_i : 8333
|
67
|
+
sockaddr = Socket.pack_sockaddr_in(port, host)
|
68
|
+
#raise "invalid IPv4 Address: #{addr}" unless sockaddr[0...2] == "\x02\x00"
|
69
|
+
port, host = sockaddr[2...4], sockaddr[4...8]
|
70
|
+
[[1].pack("Q"), "\x00"*10, "\xFF\xFF", host, port].join
|
71
|
+
end
|
72
|
+
|
73
|
+
# BIP0037: this field starts with version 70001 and is allowed to be missing, defaults to true
|
74
|
+
def unpack_relay_field(version, payload)
|
75
|
+
( version >= 70001 and payload ) ? Protocol.unpack_boolean(payload) : [ true, nil ]
|
76
|
+
end
|
77
|
+
|
78
|
+
def uptime
|
79
|
+
@fields[:time] - Time.now.tv_sec
|
80
|
+
end
|
81
|
+
|
82
|
+
def method_missing(*a); (@fields[a.first] rescue nil) or super(*a); end
|
83
|
+
|
84
|
+
def self.parse(payload); new.parse(payload); end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,1656 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require 'bitcoin'
|
4
|
+
|
5
|
+
class Bitcoin::Script
|
6
|
+
|
7
|
+
OP_0 = 0
|
8
|
+
OP_FALSE = 0
|
9
|
+
OP_1 = 81
|
10
|
+
OP_TRUE = 81
|
11
|
+
OP_2 = 0x52
|
12
|
+
OP_3 = 0x53
|
13
|
+
OP_4 = 0x54
|
14
|
+
OP_5 = 0x55
|
15
|
+
OP_6 = 0x56
|
16
|
+
OP_7 = 0x57
|
17
|
+
OP_8 = 0x58
|
18
|
+
OP_9 = 0x59
|
19
|
+
OP_10 = 0x5a
|
20
|
+
OP_11 = 0x5b
|
21
|
+
OP_12 = 0x5c
|
22
|
+
OP_13 = 0x5d
|
23
|
+
OP_14 = 0x5e
|
24
|
+
OP_15 = 0x5f
|
25
|
+
OP_16 = 0x60
|
26
|
+
|
27
|
+
OP_PUSHDATA0 = 0
|
28
|
+
OP_PUSHDATA1 = 76
|
29
|
+
OP_PUSHDATA2 = 77
|
30
|
+
OP_PUSHDATA4 = 78
|
31
|
+
OP_PUSHDATA_INVALID = 238 # 0xEE
|
32
|
+
OP_NOP = 97
|
33
|
+
OP_DUP = 118
|
34
|
+
OP_HASH160 = 169
|
35
|
+
OP_EQUAL = 135
|
36
|
+
OP_VERIFY = 105
|
37
|
+
OP_EQUALVERIFY = 136
|
38
|
+
OP_CHECKSIG = 172
|
39
|
+
OP_CHECKSIGVERIFY = 173
|
40
|
+
OP_CHECKMULTISIG = 174
|
41
|
+
OP_CHECKMULTISIGVERIFY = 175
|
42
|
+
OP_TOALTSTACK = 107
|
43
|
+
OP_FROMALTSTACK = 108
|
44
|
+
OP_TUCK = 125
|
45
|
+
OP_SWAP = 124
|
46
|
+
OP_BOOLAND = 154
|
47
|
+
OP_ADD = 147
|
48
|
+
OP_SUB = 148
|
49
|
+
OP_GREATERTHANOREQUAL = 162
|
50
|
+
OP_DROP = 117
|
51
|
+
OP_HASH256 = 170
|
52
|
+
OP_SHA256 = 168
|
53
|
+
OP_SHA1 = 167
|
54
|
+
OP_RIPEMD160 = 166
|
55
|
+
OP_NOP1 = 176
|
56
|
+
OP_NOP2 = 177
|
57
|
+
OP_NOP3 = 178
|
58
|
+
OP_NOP4 = 179
|
59
|
+
OP_NOP5 = 180
|
60
|
+
OP_NOP6 = 181
|
61
|
+
OP_NOP7 = 182
|
62
|
+
OP_NOP8 = 183
|
63
|
+
OP_NOP9 = 184
|
64
|
+
OP_NOP10 = 185
|
65
|
+
OP_CODESEPARATOR = 171
|
66
|
+
OP_MIN = 163
|
67
|
+
OP_MAX = 164
|
68
|
+
OP_2OVER = 112
|
69
|
+
OP_2ROT = 113
|
70
|
+
OP_2SWAP = 114
|
71
|
+
OP_IFDUP = 115
|
72
|
+
OP_DEPTH = 116
|
73
|
+
OP_1NEGATE = 79
|
74
|
+
OP_WITHIN = 165
|
75
|
+
OP_NUMEQUAL = 156
|
76
|
+
OP_NUMEQUALVERIFY = 157
|
77
|
+
OP_LESSTHAN = 159
|
78
|
+
OP_LESSTHANOREQUAL = 161
|
79
|
+
OP_GREATERTHAN = 160
|
80
|
+
OP_NOT = 145
|
81
|
+
OP_0NOTEQUAL = 146
|
82
|
+
OP_ABS = 144
|
83
|
+
OP_1ADD = 139
|
84
|
+
OP_1SUB = 140
|
85
|
+
OP_NEGATE = 143
|
86
|
+
OP_BOOLOR = 155
|
87
|
+
OP_NUMNOTEQUAL = 158
|
88
|
+
OP_RETURN = 106
|
89
|
+
OP_OVER = 120
|
90
|
+
OP_IF = 99
|
91
|
+
OP_NOTIF = 100
|
92
|
+
OP_ELSE = 103
|
93
|
+
OP_ENDIF = 104
|
94
|
+
OP_PICK = 121
|
95
|
+
OP_SIZE = 130
|
96
|
+
OP_VER = 98
|
97
|
+
OP_ROLL = 122
|
98
|
+
OP_ROT = 123
|
99
|
+
OP_2DROP = 109
|
100
|
+
OP_2DUP = 110
|
101
|
+
OP_3DUP = 111
|
102
|
+
OP_NIP = 119
|
103
|
+
|
104
|
+
OP_CAT = 126
|
105
|
+
OP_SUBSTR = 127
|
106
|
+
OP_LEFT = 128
|
107
|
+
OP_RIGHT = 129
|
108
|
+
OP_INVERT = 131
|
109
|
+
OP_AND = 132
|
110
|
+
OP_OR = 133
|
111
|
+
OP_XOR = 134
|
112
|
+
OP_2MUL = 141
|
113
|
+
OP_2DIV = 142
|
114
|
+
OP_MUL = 149
|
115
|
+
OP_DIV = 150
|
116
|
+
OP_MOD = 151
|
117
|
+
OP_LSHIFT = 152
|
118
|
+
OP_RSHIFT = 153
|
119
|
+
|
120
|
+
OP_INVALIDOPCODE = 0xff
|
121
|
+
|
122
|
+
OPCODES = Hash[*constants.grep(/^OP_/).map{|i| [const_get(i), i.to_s] }.flatten]
|
123
|
+
OPCODES[0] = "0"
|
124
|
+
OPCODES[81] = "1"
|
125
|
+
|
126
|
+
OPCODES_ALIAS = {
|
127
|
+
"OP_TRUE" => OP_1,
|
128
|
+
"OP_FALSE" => OP_0,
|
129
|
+
"OP_EVAL" => OP_NOP1,
|
130
|
+
"OP_CHECKHASHVERIFY" => OP_NOP2,
|
131
|
+
}
|
132
|
+
|
133
|
+
DISABLED_OPCODES = [
|
134
|
+
OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT, OP_INVERT,
|
135
|
+
OP_AND, OP_OR, OP_XOR, OP_2MUL, OP_2DIV, OP_MUL,
|
136
|
+
OP_DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT
|
137
|
+
]
|
138
|
+
|
139
|
+
OP_2_16 = (82..96).to_a
|
140
|
+
|
141
|
+
|
142
|
+
OPCODES_PARSE_BINARY = {}
|
143
|
+
OPCODES.each{|k,v| OPCODES_PARSE_BINARY[k] = v }
|
144
|
+
OP_2_16.each{|i| OPCODES_PARSE_BINARY[i] = (OP_2_16.index(i)+2).to_s }
|
145
|
+
|
146
|
+
OPCODES_PARSE_STRING = {}
|
147
|
+
OPCODES.each{|k,v| OPCODES_PARSE_STRING[v] = k }
|
148
|
+
OPCODES_ALIAS.each{|k,v| OPCODES_PARSE_STRING[k] = v }
|
149
|
+
2.upto(16).each{|i| OPCODES_PARSE_STRING["OP_#{i}"] = OP_2_16[i-2] }
|
150
|
+
2.upto(16).each{|i| OPCODES_PARSE_STRING["#{i}" ] = OP_2_16[i-2] }
|
151
|
+
[1,2,4].each{|i| OPCODES_PARSE_STRING.delete("OP_PUSHDATA#{i}") }
|
152
|
+
|
153
|
+
SIGHASH_TYPE = {
|
154
|
+
all: 1,
|
155
|
+
none: 2,
|
156
|
+
single: 3,
|
157
|
+
forkid: 64,
|
158
|
+
anyonecanpay: 128
|
159
|
+
}.freeze
|
160
|
+
|
161
|
+
attr_reader :raw, :chunks, :debug, :stack
|
162
|
+
|
163
|
+
# create a new script. +bytes+ is typically input_script + output_script
|
164
|
+
def initialize(input_script, previous_output_script=nil)
|
165
|
+
@raw_byte_sizes = [input_script.bytesize, previous_output_script ? previous_output_script.bytesize : 0]
|
166
|
+
@input_script, @previous_output_script = input_script, previous_output_script
|
167
|
+
|
168
|
+
@raw = if @previous_output_script
|
169
|
+
@input_script + [ Bitcoin::Script::OP_CODESEPARATOR ].pack("C") + @previous_output_script
|
170
|
+
else
|
171
|
+
@input_script
|
172
|
+
end
|
173
|
+
|
174
|
+
@chunks = parse(@input_script)
|
175
|
+
|
176
|
+
if previous_output_script
|
177
|
+
@script_codeseparator_index = @chunks.size
|
178
|
+
@chunks << Bitcoin::Script::OP_CODESEPARATOR
|
179
|
+
@chunks += parse(@previous_output_script)
|
180
|
+
end
|
181
|
+
|
182
|
+
@stack, @stack_alt, @exec_stack = [], [], []
|
183
|
+
@last_codeseparator_index = 0
|
184
|
+
@do_exec = true
|
185
|
+
end
|
186
|
+
|
187
|
+
class ::String
|
188
|
+
attr_accessor :bitcoin_pushdata
|
189
|
+
attr_accessor :bitcoin_pushdata_length
|
190
|
+
end
|
191
|
+
|
192
|
+
# parse raw script
|
193
|
+
def parse(bytes, offset=0)
|
194
|
+
program = bytes.unpack("C*")
|
195
|
+
chunks = []
|
196
|
+
until program.empty?
|
197
|
+
opcode = program.shift
|
198
|
+
|
199
|
+
if (opcode > 0) && (opcode < OP_PUSHDATA1)
|
200
|
+
len, tmp = opcode, program[0]
|
201
|
+
chunks << program.shift(len).pack("C*")
|
202
|
+
|
203
|
+
# 0x16 = 22 due to OP_2_16 from_string parsing
|
204
|
+
if len == 1 && tmp && tmp <= 22
|
205
|
+
chunks.last.bitcoin_pushdata = OP_PUSHDATA0
|
206
|
+
chunks.last.bitcoin_pushdata_length = len
|
207
|
+
else
|
208
|
+
raise "invalid OP_PUSHDATA0" if len != chunks.last.bytesize
|
209
|
+
end
|
210
|
+
elsif (opcode == OP_PUSHDATA1)
|
211
|
+
len = program.shift(1)[0]
|
212
|
+
chunks << program.shift(len).pack("C*")
|
213
|
+
|
214
|
+
unless len > OP_PUSHDATA1 && len <= 0xff
|
215
|
+
chunks.last.bitcoin_pushdata = OP_PUSHDATA1
|
216
|
+
chunks.last.bitcoin_pushdata_length = len
|
217
|
+
else
|
218
|
+
raise "invalid OP_PUSHDATA1" if len != chunks.last.bytesize
|
219
|
+
end
|
220
|
+
elsif (opcode == OP_PUSHDATA2)
|
221
|
+
len = program.shift(2).pack("C*").unpack("v")[0]
|
222
|
+
chunks << program.shift(len).pack("C*")
|
223
|
+
|
224
|
+
unless len > 0xff && len <= 0xffff
|
225
|
+
chunks.last.bitcoin_pushdata = OP_PUSHDATA2
|
226
|
+
chunks.last.bitcoin_pushdata_length = len
|
227
|
+
else
|
228
|
+
raise "invalid OP_PUSHDATA2" if len != chunks.last.bytesize
|
229
|
+
end
|
230
|
+
elsif (opcode == OP_PUSHDATA4)
|
231
|
+
len = program.shift(4).pack("C*").unpack("V")[0]
|
232
|
+
chunks << program.shift(len).pack("C*")
|
233
|
+
|
234
|
+
unless len > 0xffff # && len <= 0xffffffff
|
235
|
+
chunks.last.bitcoin_pushdata = OP_PUSHDATA4
|
236
|
+
chunks.last.bitcoin_pushdata_length = len
|
237
|
+
else
|
238
|
+
raise "invalid OP_PUSHDATA4" if len != chunks.last.bytesize
|
239
|
+
end
|
240
|
+
else
|
241
|
+
chunks << opcode
|
242
|
+
end
|
243
|
+
end
|
244
|
+
chunks
|
245
|
+
rescue => ex
|
246
|
+
# bail out! #run returns false but serialization roundtrips still create the right payload.
|
247
|
+
chunks.pop if ex.message.include?("invalid OP_PUSHDATA")
|
248
|
+
@parse_invalid = true
|
249
|
+
c = bytes.unpack("C*").pack("C*")
|
250
|
+
c.bitcoin_pushdata = OP_PUSHDATA_INVALID
|
251
|
+
c.bitcoin_pushdata_length = c.bytesize
|
252
|
+
chunks << c
|
253
|
+
end
|
254
|
+
|
255
|
+
# string representation of the script
|
256
|
+
def to_string(chunks=nil)
|
257
|
+
string = ""
|
258
|
+
(chunks || @chunks).each.with_index{|i,idx|
|
259
|
+
string << " " unless idx == 0
|
260
|
+
string << case i
|
261
|
+
when Fixnum
|
262
|
+
if opcode = OPCODES_PARSE_BINARY[i]
|
263
|
+
opcode
|
264
|
+
else
|
265
|
+
"(opcode-#{i})"
|
266
|
+
end
|
267
|
+
when String
|
268
|
+
if i.bitcoin_pushdata
|
269
|
+
"#{i.bitcoin_pushdata}:#{i.bitcoin_pushdata_length}:".force_encoding('binary') + i.unpack("H*")[0]
|
270
|
+
else
|
271
|
+
i.unpack("H*")[0]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
}
|
275
|
+
string
|
276
|
+
end
|
277
|
+
|
278
|
+
def to_binary(chunks=nil)
|
279
|
+
(chunks || @chunks).map{|chunk|
|
280
|
+
case chunk
|
281
|
+
when Fixnum; [chunk].pack("C*")
|
282
|
+
when String; self.class.pack_pushdata(chunk)
|
283
|
+
end
|
284
|
+
}.join
|
285
|
+
end
|
286
|
+
alias :to_payload :to_binary
|
287
|
+
|
288
|
+
def to_binary_without_signatures(drop_signatures, chunks=nil)
|
289
|
+
buf = []
|
290
|
+
(chunks || @chunks).each.with_index{|chunk,idx|
|
291
|
+
if chunk == OP_CODESEPARATOR and idx <= @last_codeseparator_index
|
292
|
+
buf.clear
|
293
|
+
elsif chunk == OP_CODESEPARATOR
|
294
|
+
if idx == @script_codeseparator_index
|
295
|
+
break
|
296
|
+
else
|
297
|
+
# skip
|
298
|
+
end
|
299
|
+
elsif drop_signatures.none?{|e| e == chunk }
|
300
|
+
buf << chunk
|
301
|
+
end
|
302
|
+
}
|
303
|
+
to_binary(buf)
|
304
|
+
end
|
305
|
+
|
306
|
+
# Returns a script that deleted the script before the index specified by separator_index.
|
307
|
+
def subscript_codeseparator(separator_index)
|
308
|
+
buf = []
|
309
|
+
process_separator_index = 0
|
310
|
+
(chunks || @chunks).each{|chunk|
|
311
|
+
buf << chunk if process_separator_index == separator_index
|
312
|
+
process_separator_index += 1 if chunk == OP_CODESEPARATOR and process_separator_index < separator_index
|
313
|
+
}
|
314
|
+
to_binary(buf)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Adds opcode (OP_0, OP_1, ... OP_CHECKSIG etc.)
|
318
|
+
# Returns self.
|
319
|
+
def append_opcode(opcode)
|
320
|
+
raise "Opcode should be a Fixnum" if !opcode.is_a?(Fixnum)
|
321
|
+
if opcode >= OP_0 && opcode <= 0xff
|
322
|
+
@chunks << opcode
|
323
|
+
else
|
324
|
+
raise "Opcode should be within [0x00, 0xff]"
|
325
|
+
end
|
326
|
+
self
|
327
|
+
end
|
328
|
+
|
329
|
+
# Adds the opcode corresponding to the given number. Returns self.
|
330
|
+
def append_number(number)
|
331
|
+
opcode =
|
332
|
+
case number
|
333
|
+
when -1 then OP_1NEGATE
|
334
|
+
when 0 then OP_0
|
335
|
+
when 1 then OP_1
|
336
|
+
when 2..16 then OP_2 + (16 - number)
|
337
|
+
end
|
338
|
+
raise "No opcode for number #{number}" if opcode.nil?
|
339
|
+
append_opcode(opcode)
|
340
|
+
end
|
341
|
+
|
342
|
+
# Adds binary string as pushdata. Pushdata will be encoded in the most compact form
|
343
|
+
# (unless the string contains internal info about serialization that's added by Script class)
|
344
|
+
# Returns self.
|
345
|
+
def append_pushdata(pushdata_string)
|
346
|
+
raise "Pushdata should be a string" if !pushdata_string.is_a?(String)
|
347
|
+
@chunks << pushdata_string
|
348
|
+
self
|
349
|
+
end
|
350
|
+
|
351
|
+
def self.pack_pushdata(data)
|
352
|
+
size = data.bytesize
|
353
|
+
|
354
|
+
if data.bitcoin_pushdata
|
355
|
+
size = data.bitcoin_pushdata_length
|
356
|
+
pack_pushdata_align(data.bitcoin_pushdata, size, data)
|
357
|
+
else
|
358
|
+
head = if size < OP_PUSHDATA1
|
359
|
+
[size].pack("C")
|
360
|
+
elsif size <= 0xff
|
361
|
+
[OP_PUSHDATA1, size].pack("CC")
|
362
|
+
elsif size <= 0xffff
|
363
|
+
[OP_PUSHDATA2, size].pack("Cv")
|
364
|
+
#elsif size <= 0xffffffff
|
365
|
+
else
|
366
|
+
[OP_PUSHDATA4, size].pack("CV")
|
367
|
+
end
|
368
|
+
head + data
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def self.pack_pushdata_align(pushdata, len, data)
|
373
|
+
case pushdata
|
374
|
+
when OP_PUSHDATA1
|
375
|
+
[OP_PUSHDATA1, len].pack("CC") + data
|
376
|
+
when OP_PUSHDATA2
|
377
|
+
[OP_PUSHDATA2, len].pack("Cv") + data
|
378
|
+
when OP_PUSHDATA4
|
379
|
+
[OP_PUSHDATA4, len].pack("CV") + data
|
380
|
+
when OP_PUSHDATA_INVALID
|
381
|
+
data
|
382
|
+
else # OP_PUSHDATA0
|
383
|
+
[len].pack("C") + data
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
# script object of a string representation
|
388
|
+
def self.from_string(input_script, previous_output_script=nil)
|
389
|
+
if previous_output_script
|
390
|
+
new(binary_from_string(input_script), binary_from_string(previous_output_script))
|
391
|
+
else
|
392
|
+
new(binary_from_string(input_script))
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
class ScriptOpcodeError < StandardError; end
|
397
|
+
|
398
|
+
# raw script binary of a string representation
|
399
|
+
def self.binary_from_string(script_string)
|
400
|
+
buf = ""
|
401
|
+
script_string.split(" ").each{|i|
|
402
|
+
i = if opcode = OPCODES_PARSE_STRING[i]
|
403
|
+
opcode
|
404
|
+
else
|
405
|
+
case i
|
406
|
+
when /OP_PUSHDATA/ # skip
|
407
|
+
when /OP_(.+)$/; raise ScriptOpcodeError, "#{i} not defined!"
|
408
|
+
when /\(opcode\-(\d+)\)/; $1.to_i
|
409
|
+
when "(opcode"; # skip # fix invalid opcode parsing
|
410
|
+
when /^(\d+)\)/; $1.to_i # fix invalid opcode parsing
|
411
|
+
when /(\d+):(\d+):(.+)?/
|
412
|
+
pushdata, len, data = $1.to_i, $2.to_i, $3
|
413
|
+
pack_pushdata_align(pushdata, len, [data].pack("H*"))
|
414
|
+
else
|
415
|
+
data = [i].pack("H*")
|
416
|
+
pack_pushdata(data)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
buf << if i.is_a?(Fixnum)
|
421
|
+
i < 256 ? [i].pack("C") : [OpenSSL::BN.new(i.to_s,10).to_hex].pack("H*")
|
422
|
+
else
|
423
|
+
i
|
424
|
+
end if i
|
425
|
+
}
|
426
|
+
buf
|
427
|
+
end
|
428
|
+
|
429
|
+
def invalid?
|
430
|
+
@script_invalid ||= false
|
431
|
+
end
|
432
|
+
|
433
|
+
# run the script. +check_callback+ is called for OP_CHECKSIG operations
|
434
|
+
def run(block_timestamp=Time.now.to_i, opts={}, &check_callback)
|
435
|
+
return false if @parse_invalid
|
436
|
+
|
437
|
+
#p [to_string, block_timestamp, is_p2sh?]
|
438
|
+
@script_invalid = true if @raw_byte_sizes.any?{|size| size > 10_000 }
|
439
|
+
@last_codeseparator_index = 0
|
440
|
+
|
441
|
+
if block_timestamp >= 1333238400 # Pay to Script Hash (BIP 0016)
|
442
|
+
return pay_to_script_hash(block_timestamp, opts, check_callback) if is_p2sh?
|
443
|
+
end
|
444
|
+
|
445
|
+
@debug = []
|
446
|
+
@chunks.each.with_index{|chunk,idx|
|
447
|
+
break if invalid?
|
448
|
+
@chunk_last_index = idx
|
449
|
+
|
450
|
+
@debug << @stack.map{|i| i.unpack("H*") rescue i}
|
451
|
+
@do_exec = @exec_stack.count(false) == 0 ? true : false
|
452
|
+
#p [@stack, @do_exec]
|
453
|
+
|
454
|
+
case chunk
|
455
|
+
when Fixnum
|
456
|
+
if DISABLED_OPCODES.include?(chunk)
|
457
|
+
@script_invalid = true
|
458
|
+
@debug << "DISABLED_#{OPCODES[chunk]}"
|
459
|
+
break
|
460
|
+
end
|
461
|
+
|
462
|
+
next @debug.pop unless (@do_exec || (OP_IF <= chunk && chunk <= OP_ENDIF))
|
463
|
+
|
464
|
+
case chunk
|
465
|
+
when *OPCODES_METHOD.keys
|
466
|
+
m = method( n=OPCODES_METHOD[chunk] )
|
467
|
+
@debug << n.to_s.upcase
|
468
|
+
# invoke opcode method
|
469
|
+
case m.arity
|
470
|
+
when 0
|
471
|
+
m.call
|
472
|
+
when 1
|
473
|
+
m.call(check_callback)
|
474
|
+
when -2 # One fixed parameter, one optional
|
475
|
+
m.call(check_callback, opts)
|
476
|
+
else
|
477
|
+
puts "Bitcoin::Script: opcode #{name} method parameters invalid"
|
478
|
+
end
|
479
|
+
when *OP_2_16
|
480
|
+
@stack << OP_2_16.index(chunk) + 2
|
481
|
+
@debug << "OP_#{chunk-80}"
|
482
|
+
else
|
483
|
+
name = OPCODES[chunk] || chunk
|
484
|
+
puts "Bitcoin::Script: opcode #{name} unkown or not implemented\n#{to_string.inspect}"
|
485
|
+
raise "opcode #{name} unkown or not implemented"
|
486
|
+
end
|
487
|
+
when String
|
488
|
+
if @do_exec
|
489
|
+
@debug << "PUSH DATA #{chunk.unpack("H*")[0]}"
|
490
|
+
@stack << chunk
|
491
|
+
else
|
492
|
+
@debug.pop
|
493
|
+
end
|
494
|
+
end
|
495
|
+
}
|
496
|
+
@debug << @stack.map{|i| i.unpack("H*") rescue i } #if @do_exec
|
497
|
+
|
498
|
+
if @script_invalid
|
499
|
+
@stack << 0
|
500
|
+
@debug << "INVALID TRANSACTION"
|
501
|
+
end
|
502
|
+
|
503
|
+
@debug << "RESULT"
|
504
|
+
return false if @stack.empty?
|
505
|
+
return false if cast_to_bool(@stack.pop) == false
|
506
|
+
true
|
507
|
+
end
|
508
|
+
|
509
|
+
def invalid
|
510
|
+
@script_invalid = true; nil
|
511
|
+
end
|
512
|
+
|
513
|
+
def self.drop_signatures(script_pubkey, drop_signatures)
|
514
|
+
script = new(script_pubkey).to_string.split(" ").delete_if{|c| drop_signatures.include?(c) }.join(" ")
|
515
|
+
script_pubkey = binary_from_string(script)
|
516
|
+
end
|
517
|
+
|
518
|
+
# pay_to_script_hash: https://en.bitcoin.it/wiki/BIP_0016
|
519
|
+
#
|
520
|
+
# <sig> {<pub> OP_CHECKSIG} | OP_HASH160 <script_hash> OP_EQUAL
|
521
|
+
def pay_to_script_hash(block_timestamp, opts, check_callback)
|
522
|
+
return false if @chunks.size < 4
|
523
|
+
*rest, script, _, script_hash, _ = @chunks
|
524
|
+
script = rest.pop if script == OP_CODESEPARATOR
|
525
|
+
script, script_hash = cast_to_string(script), cast_to_string(script_hash)
|
526
|
+
|
527
|
+
return false unless Bitcoin.hash160(script.unpack("H*")[0]) == script_hash.unpack("H*")[0]
|
528
|
+
return true if check_callback == :check
|
529
|
+
|
530
|
+
script = self.class.new(to_binary(rest) + script).inner_p2sh!(script)
|
531
|
+
result = script.run(block_timestamp, opts, &check_callback)
|
532
|
+
@debug = script.debug
|
533
|
+
@stack = script.stack # Set the execution stack to match the redeem script, so checks on stack contents at end of script execution validate correctly
|
534
|
+
result
|
535
|
+
end
|
536
|
+
|
537
|
+
def inner_p2sh!(script=nil); @inner_p2sh = true; @inner_script_code = script; self; end
|
538
|
+
def inner_p2sh?; @inner_p2sh; end
|
539
|
+
|
540
|
+
# get the inner p2sh script
|
541
|
+
def inner_p2sh_script
|
542
|
+
return nil if @chunks.size < 4
|
543
|
+
*rest, script, _, script_hash, _ = @chunks
|
544
|
+
script = rest.pop if script == OP_CODESEPARATOR
|
545
|
+
script, script_hash = cast_to_string(script), cast_to_string(script_hash)
|
546
|
+
|
547
|
+
return nil unless Bitcoin.hash160(script.unpack("H*")[0]) == script_hash.unpack("H*")[0]
|
548
|
+
script
|
549
|
+
end
|
550
|
+
|
551
|
+
# is this a :script_hash (pay-to-script-hash/p2sh) script?
|
552
|
+
def is_pay_to_script_hash?
|
553
|
+
return false if @inner_p2sh
|
554
|
+
if @previous_output_script
|
555
|
+
chunks = Bitcoin::Script.new(@previous_output_script).chunks
|
556
|
+
chunks.size == 3 &&
|
557
|
+
chunks[-3] == OP_HASH160 &&
|
558
|
+
chunks[-2].is_a?(String) && chunks[-2].bytesize == 20 &&
|
559
|
+
chunks[-1] == OP_EQUAL
|
560
|
+
else
|
561
|
+
@chunks.size >= 3 &&
|
562
|
+
@chunks[-3] == OP_HASH160 &&
|
563
|
+
@chunks[-2].is_a?(String) && @chunks[-2].bytesize == 20 &&
|
564
|
+
@chunks[-1] == OP_EQUAL &&
|
565
|
+
# make sure the script_sig matches the p2sh hash from the pk_script (if there is one)
|
566
|
+
(@chunks.size > 3 ? pay_to_script_hash(nil, nil, :check) : true)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
alias :is_p2sh? :is_pay_to_script_hash?
|
570
|
+
|
571
|
+
# check if script is in one of the recognized standard formats
|
572
|
+
def is_standard?
|
573
|
+
is_pubkey? || is_hash160? || is_multisig? || is_p2sh? || is_op_return? || is_witness_v0_keyhash? || is_witness_v0_scripthash?
|
574
|
+
end
|
575
|
+
|
576
|
+
# is this a pubkey script
|
577
|
+
def is_pubkey?
|
578
|
+
return false if @chunks.size != 2
|
579
|
+
(@chunks[1] == OP_CHECKSIG) && @chunks[0] && (@chunks[0].is_a?(String)) && @chunks[0] != OP_RETURN
|
580
|
+
end
|
581
|
+
alias :is_send_to_ip? :is_pubkey?
|
582
|
+
|
583
|
+
# is this a hash160 (address) script
|
584
|
+
def is_hash160?
|
585
|
+
return false if @chunks.size != 5
|
586
|
+
(@chunks[0..1] + @chunks[-2..-1]) ==
|
587
|
+
[OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG] &&
|
588
|
+
@chunks[2].is_a?(String) && @chunks[2].bytesize == 20
|
589
|
+
end
|
590
|
+
|
591
|
+
# is this a multisig script
|
592
|
+
def is_multisig?
|
593
|
+
return false if @chunks.size < 4 || !@chunks[-2].is_a?(Fixnum)
|
594
|
+
@chunks[-1] == OP_CHECKMULTISIG and get_multisig_pubkeys.all?{|c| c.is_a?(String) }
|
595
|
+
end
|
596
|
+
|
597
|
+
# is this an op_return script
|
598
|
+
def is_op_return?
|
599
|
+
@chunks[0] == OP_RETURN && @chunks.size <= 2
|
600
|
+
end
|
601
|
+
|
602
|
+
# is this a witness script(witness_v0_keyhash or witness_v0_scripthash)
|
603
|
+
def is_witness?
|
604
|
+
is_witness_v0_keyhash? || is_witness_v0_scripthash?
|
605
|
+
end
|
606
|
+
|
607
|
+
# is this a witness pubkey script
|
608
|
+
def is_witness_v0_keyhash?
|
609
|
+
@chunks.length == 2 &&@chunks[0] == 0 && @chunks[1].is_a?(String) && @chunks[1].bytesize == 20
|
610
|
+
end
|
611
|
+
|
612
|
+
# is this a witness script hash
|
613
|
+
def is_witness_v0_scripthash?
|
614
|
+
@chunks.length == 2 &&@chunks[0] == 0 && @chunks[1].is_a?(String) && @chunks[1].bytesize == 32
|
615
|
+
end
|
616
|
+
|
617
|
+
# Verify the script is only pushing data onto the stack
|
618
|
+
def is_push_only?(script_data=nil)
|
619
|
+
check_pushes(push_only=true, canonical_only=false, (script_data||@input_script))
|
620
|
+
end
|
621
|
+
|
622
|
+
# Make sure opcodes used to push data match their intended length ranges
|
623
|
+
def pushes_are_canonical?(script_data=nil)
|
624
|
+
check_pushes(push_only=false, canonical_only=true, (script_data||@raw))
|
625
|
+
end
|
626
|
+
|
627
|
+
def check_pushes(push_only=true, canonical_only=false, buf)
|
628
|
+
program = buf.unpack("C*")
|
629
|
+
until program.empty?
|
630
|
+
opcode = program.shift
|
631
|
+
if opcode > OP_16
|
632
|
+
return false if push_only
|
633
|
+
next
|
634
|
+
end
|
635
|
+
if opcode < OP_PUSHDATA1 && opcode > OP_0
|
636
|
+
# Could have used an OP_n code, rather than a 1-byte push.
|
637
|
+
return false if canonical_only && opcode == 1 && program[0] <= 16
|
638
|
+
program.shift(opcode)
|
639
|
+
end
|
640
|
+
if opcode == OP_PUSHDATA1
|
641
|
+
len = program.shift(1)[0]
|
642
|
+
# Could have used a normal n-byte push, rather than OP_PUSHDATA1.
|
643
|
+
return false if canonical_only && len < OP_PUSHDATA1
|
644
|
+
program.shift(len)
|
645
|
+
end
|
646
|
+
if opcode == OP_PUSHDATA2
|
647
|
+
len = program.shift(2).pack("C*").unpack("v")[0]
|
648
|
+
# Could have used an OP_PUSHDATA1.
|
649
|
+
return false if canonical_only && len <= 0xff
|
650
|
+
program.shift(len)
|
651
|
+
end
|
652
|
+
if opcode == OP_PUSHDATA4
|
653
|
+
len = program.shift(4).pack("C*").unpack("V")[0]
|
654
|
+
# Could have used an OP_PUSHDATA2.
|
655
|
+
return false if canonical_only && len <= 0xffff
|
656
|
+
program.shift(len)
|
657
|
+
end
|
658
|
+
end
|
659
|
+
true
|
660
|
+
rescue
|
661
|
+
# catch parsing errors
|
662
|
+
false
|
663
|
+
end
|
664
|
+
|
665
|
+
# get type of this tx
|
666
|
+
def type
|
667
|
+
if is_hash160?; :hash160
|
668
|
+
elsif is_pubkey?; :pubkey
|
669
|
+
elsif is_multisig?; :multisig
|
670
|
+
elsif is_p2sh?; :p2sh
|
671
|
+
elsif is_op_return?; :op_return
|
672
|
+
elsif is_witness_v0_keyhash?; :witness_v0_keyhash
|
673
|
+
elsif is_witness_v0_scripthash?;:witness_v0_scripthash
|
674
|
+
else; :unknown
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
# get the public key for this pubkey script
|
679
|
+
def get_pubkey
|
680
|
+
return @chunks[0].unpack("H*")[0] if @chunks.size == 1
|
681
|
+
is_pubkey? ? @chunks[0].unpack("H*")[0] : nil
|
682
|
+
end
|
683
|
+
|
684
|
+
# get the pubkey address for this pubkey script
|
685
|
+
def get_pubkey_address
|
686
|
+
Bitcoin.pubkey_to_address(get_pubkey)
|
687
|
+
end
|
688
|
+
|
689
|
+
# get the hash160 for this hash160 or pubkey script
|
690
|
+
def get_hash160
|
691
|
+
return @chunks[2..-3][0].unpack("H*")[0] if is_hash160?
|
692
|
+
return @chunks[-2].unpack("H*")[0] if is_p2sh?
|
693
|
+
return Bitcoin.hash160(get_pubkey) if is_pubkey?
|
694
|
+
return @chunks[1].unpack("H*")[0] if is_witness_v0_keyhash?
|
695
|
+
return @chunks[1].unpack("H*")[0] if is_witness_v0_scripthash?
|
696
|
+
end
|
697
|
+
|
698
|
+
# get the hash160 address for this hash160 script
|
699
|
+
def get_hash160_address
|
700
|
+
Bitcoin.hash160_to_address(get_hash160)
|
701
|
+
end
|
702
|
+
|
703
|
+
# get the public keys for this multisig script
|
704
|
+
def get_multisig_pubkeys
|
705
|
+
1.upto(@chunks[-2] - 80).map{|i| @chunks[i] }
|
706
|
+
end
|
707
|
+
|
708
|
+
# get the pubkey addresses for this multisig script
|
709
|
+
def get_multisig_addresses
|
710
|
+
get_multisig_pubkeys.map{|pub|
|
711
|
+
begin
|
712
|
+
Bitcoin::Key.new(nil, pub.unpack("H*")[0]).addr
|
713
|
+
rescue OpenSSL::PKey::ECError, OpenSSL::PKey::EC::Point::Error
|
714
|
+
end
|
715
|
+
}
|
716
|
+
end
|
717
|
+
|
718
|
+
def get_p2sh_address
|
719
|
+
Bitcoin.hash160_to_p2sh_address(get_hash160)
|
720
|
+
end
|
721
|
+
|
722
|
+
# get the data possibly included in an OP_RETURN script
|
723
|
+
def get_op_return_data
|
724
|
+
return nil unless is_op_return?
|
725
|
+
cast_to_string(@chunks[1]).unpack("H*")[0] if @chunks[1]
|
726
|
+
end
|
727
|
+
|
728
|
+
# get all addresses this script corresponds to (if possible)
|
729
|
+
def get_addresses
|
730
|
+
return [get_pubkey_address] if is_pubkey?
|
731
|
+
return [get_hash160_address] if is_hash160?
|
732
|
+
return get_multisig_addresses if is_multisig?
|
733
|
+
return [get_p2sh_address] if is_p2sh?
|
734
|
+
[]
|
735
|
+
end
|
736
|
+
|
737
|
+
# get single address, or first for multisig script
|
738
|
+
def get_address
|
739
|
+
addrs = get_addresses
|
740
|
+
addrs.is_a?(Array) ? addrs[0] : addrs
|
741
|
+
end
|
742
|
+
|
743
|
+
# generate pubkey tx script for given +pubkey+. returns a raw binary script of the form:
|
744
|
+
# <pubkey> OP_CHECKSIG
|
745
|
+
def self.to_pubkey_script(pubkey)
|
746
|
+
pack_pushdata([pubkey].pack("H*")) + [ OP_CHECKSIG ].pack("C")
|
747
|
+
end
|
748
|
+
|
749
|
+
# generate hash160 tx for given +address+. returns a raw binary script of the form:
|
750
|
+
# OP_DUP OP_HASH160 <hash160> OP_EQUALVERIFY OP_CHECKSIG
|
751
|
+
def self.to_hash160_script(hash160)
|
752
|
+
return nil unless hash160
|
753
|
+
# DUP HASH160 length hash160 EQUALVERIFY CHECKSIG
|
754
|
+
[ ["76", "a9", "14", hash160, "88", "ac"].join ].pack("H*")
|
755
|
+
end
|
756
|
+
|
757
|
+
# generate p2sh output script for given +p2sh+ hash160. returns a raw binary script of the form:
|
758
|
+
# OP_HASH160 <p2sh> OP_EQUAL
|
759
|
+
def self.to_p2sh_script(p2sh)
|
760
|
+
return nil unless p2sh
|
761
|
+
# HASH160 length hash EQUAL
|
762
|
+
[ ["a9", "14", p2sh, "87"].join ].pack("H*")
|
763
|
+
end
|
764
|
+
|
765
|
+
# generate p2wpkh tx for given +address+. returns a raw binary script of the form:
|
766
|
+
# 0 <hash160>
|
767
|
+
def self.to_witness_hash160_script(hash160)
|
768
|
+
return nil unless hash160
|
769
|
+
# witness ver length hash160
|
770
|
+
[ ["00", "14", hash160].join ].pack("H*")
|
771
|
+
end
|
772
|
+
|
773
|
+
# generate p2wsh output script for given +p2sh+ sha256. returns a raw binary script of the form:
|
774
|
+
# 0 <p2sh>
|
775
|
+
def self.to_witness_p2sh_script(p2sh)
|
776
|
+
return nil unless p2sh
|
777
|
+
# witness ver length sha256
|
778
|
+
[ [ "00", "20", p2sh].join].pack("H*")
|
779
|
+
end
|
780
|
+
|
781
|
+
# generate hash160 or p2sh output script, depending on the type of the given +address+.
|
782
|
+
# see #to_hash160_script and #to_p2sh_script.
|
783
|
+
def self.to_address_script(address)
|
784
|
+
hash160 = Bitcoin.hash160_from_address(address)
|
785
|
+
case Bitcoin.address_type(address)
|
786
|
+
when :hash160; to_hash160_script(hash160)
|
787
|
+
when :p2sh; to_p2sh_script(hash160)
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
# generate multisig output script for given +pubkeys+, expecting +m+ signatures.
|
792
|
+
# returns a raw binary script of the form:
|
793
|
+
# <m> <pubkey> [<pubkey> ...] <n_pubkeys> OP_CHECKMULTISIG
|
794
|
+
def self.to_multisig_script(m, *pubkeys)
|
795
|
+
raise "invalid m-of-n number" unless [m, pubkeys.size].all?{|i| (0..20).include?(i) }
|
796
|
+
raise "invalid m-of-n number" if pubkeys.size < m
|
797
|
+
pubs = pubkeys.map{|pk| pack_pushdata([pk].pack("H*")) }
|
798
|
+
|
799
|
+
m = m > 16 ? pack_pushdata([m].pack("C")) : [80 + m.to_i].pack("C")
|
800
|
+
n = pubkeys.size > 16 ? pack_pushdata([pubkeys.size].pack("C")) : [80 + pubs.size].pack("C")
|
801
|
+
|
802
|
+
[ m, *pubs, n, [OP_CHECKMULTISIG].pack("C")].join
|
803
|
+
end
|
804
|
+
|
805
|
+
# generate OP_RETURN output script with given data. returns a raw binary script of the form:
|
806
|
+
# OP_RETURN <data>
|
807
|
+
def self.to_op_return_script(data = nil)
|
808
|
+
buf = [ OP_RETURN ].pack("C")
|
809
|
+
return buf unless data
|
810
|
+
return buf + pack_pushdata( [data].pack("H*") )
|
811
|
+
end
|
812
|
+
|
813
|
+
# generate input script sig spending a pubkey output with given +signature+ and +pubkey+.
|
814
|
+
# returns a raw binary script sig of the form:
|
815
|
+
# <signature> [<pubkey>]
|
816
|
+
def self.to_pubkey_script_sig(signature, pubkey, hash_type = SIGHASH_TYPE[:all])
|
817
|
+
buf = pack_pushdata(signature + [hash_type].pack("C"))
|
818
|
+
return buf unless pubkey
|
819
|
+
|
820
|
+
expected_size = case pubkey[0]
|
821
|
+
when "\x04"; 65
|
822
|
+
when "\x02", "\x03"; 33
|
823
|
+
end
|
824
|
+
|
825
|
+
raise "pubkey is not in binary form" if !expected_size || pubkey.bytesize != expected_size
|
826
|
+
|
827
|
+
return buf + pack_pushdata(pubkey)
|
828
|
+
end
|
829
|
+
|
830
|
+
# generate p2sh multisig output script for given +args+.
|
831
|
+
# returns the p2sh output script, and the redeem script needed to spend it.
|
832
|
+
# see #to_multisig_script for the redeem script, and #to_p2sh_script for the p2sh script.
|
833
|
+
def self.to_p2sh_multisig_script(*args)
|
834
|
+
redeem_script = to_multisig_script(*args)
|
835
|
+
p2sh_script = to_p2sh_script(Bitcoin.hash160(redeem_script.hth))
|
836
|
+
return p2sh_script, redeem_script
|
837
|
+
end
|
838
|
+
|
839
|
+
# alias for #to_pubkey_script_sig
|
840
|
+
def self.to_signature_pubkey_script(*a)
|
841
|
+
to_pubkey_script_sig(*a)
|
842
|
+
end
|
843
|
+
|
844
|
+
# generate input script sig spending a multisig output script.
|
845
|
+
# returns a raw binary script sig of the form:
|
846
|
+
# OP_0 <sig> [<sig> ...]
|
847
|
+
def self.to_multisig_script_sig(*sigs)
|
848
|
+
hash_type = sigs.last.is_a?(Numeric) ? sigs.pop : SIGHASH_TYPE[:all]
|
849
|
+
partial_script = [OP_0].pack("C*")
|
850
|
+
sigs.reverse_each{ |sig| partial_script = add_sig_to_multisig_script_sig(sig, partial_script, hash_type) }
|
851
|
+
partial_script
|
852
|
+
end
|
853
|
+
|
854
|
+
# take a multisig script sig (or p2sh multisig script sig) and add
|
855
|
+
# another signature to it after the OP_0. Used to sign a tx by
|
856
|
+
# multiple parties. Signatures must be in the same order as the
|
857
|
+
# pubkeys in the output script being redeemed.
|
858
|
+
def self.add_sig_to_multisig_script_sig(sig, script_sig, hash_type = SIGHASH_TYPE[:all])
|
859
|
+
signature = sig + [hash_type].pack("C*")
|
860
|
+
offset = script_sig.empty? ? 0 : 1
|
861
|
+
script_sig.insert(offset, pack_pushdata(signature))
|
862
|
+
end
|
863
|
+
|
864
|
+
# generate input script sig spending a p2sh-multisig output script.
|
865
|
+
# returns a raw binary script sig of the form:
|
866
|
+
# OP_0 <sig> [<sig> ...] <redeem_script>
|
867
|
+
def self.to_p2sh_multisig_script_sig(redeem_script, *sigs)
|
868
|
+
to_multisig_script_sig(*sigs.flatten) + pack_pushdata(redeem_script)
|
869
|
+
end
|
870
|
+
|
871
|
+
# Sort signatures in the given +script_sig+ according to the order of pubkeys in
|
872
|
+
# the redeem script. Also needs the +sig_hash+ to match signatures to pubkeys.
|
873
|
+
def self.sort_p2sh_multisig_signatures script_sig, sig_hash
|
874
|
+
script = new(script_sig)
|
875
|
+
redeem_script = new(script.chunks[-1])
|
876
|
+
pubkeys = redeem_script.get_multisig_pubkeys
|
877
|
+
|
878
|
+
# find the pubkey for each signature by trying to verify it
|
879
|
+
sigs = Hash[script.chunks[1...-1].map.with_index do |sig, idx|
|
880
|
+
pubkey = pubkeys.map {|key|
|
881
|
+
Bitcoin::Key.new(nil, key.hth).verify(sig_hash, sig) ? key : nil }.compact.first
|
882
|
+
raise "Key for signature ##{idx} not found in redeem script!" unless pubkey
|
883
|
+
[pubkey, sig]
|
884
|
+
end]
|
885
|
+
|
886
|
+
[OP_0].pack("C*") + pubkeys.map {|k| sigs[k] ? pack_pushdata(sigs[k]) : nil }.join +
|
887
|
+
pack_pushdata(redeem_script.raw)
|
888
|
+
end
|
889
|
+
|
890
|
+
def get_signatures_required
|
891
|
+
return false unless is_multisig?
|
892
|
+
@chunks[0] - 80
|
893
|
+
end
|
894
|
+
|
895
|
+
def get_keys_provided
|
896
|
+
return false unless is_multisig?
|
897
|
+
@chunks[-2] - 80
|
898
|
+
end
|
899
|
+
|
900
|
+
def codeseparator_count
|
901
|
+
@chunks.select{|c|c == Bitcoin::Script::OP_CODESEPARATOR}.length
|
902
|
+
end
|
903
|
+
|
904
|
+
# This matches CScript::GetSigOpCount(bool fAccurate)
|
905
|
+
# Note: this does not cover P2SH script which is to be unserialized
|
906
|
+
# and checked explicitly when validating blocks.
|
907
|
+
def sigops_count_accurate(is_accurate)
|
908
|
+
count = 0
|
909
|
+
last_opcode = nil
|
910
|
+
@chunks.each do |chunk| # pushdate or opcode
|
911
|
+
if chunk == OP_CHECKSIG || chunk == OP_CHECKSIGVERIFY
|
912
|
+
count += 1
|
913
|
+
elsif chunk == OP_CHECKMULTISIG || chunk == OP_CHECKMULTISIGVERIFY
|
914
|
+
# Accurate mode counts exact number of pubkeys required (not signatures, but pubkeys!). Only used in P2SH scripts.
|
915
|
+
# Inaccurate mode counts every multisig as 20 signatures.
|
916
|
+
if is_accurate && last_opcode && last_opcode.is_a?(Fixnum) && last_opcode >= OP_1 && last_opcode <= OP_16
|
917
|
+
count += ::Bitcoin::Script.decode_OP_N(last_opcode)
|
918
|
+
else
|
919
|
+
count += 20
|
920
|
+
end
|
921
|
+
end
|
922
|
+
last_opcode = chunk
|
923
|
+
end
|
924
|
+
count
|
925
|
+
end
|
926
|
+
|
927
|
+
# This method applies to script_sig that is an input for p2sh output.
|
928
|
+
# Bitcoind has somewhat special way to return count for invalid input scripts:
|
929
|
+
# it returns 0 when the opcode can't be parsed or when it's over OP_16.
|
930
|
+
# Also, if the OP_{N} is used anywhere it's treated as 0-length data.
|
931
|
+
# See CScript::GetSigOpCount(const CScript& scriptSig) in bitcoind.
|
932
|
+
def sigops_count_for_p2sh
|
933
|
+
# This is a pay-to-script-hash scriptPubKey;
|
934
|
+
# get the last item that the scriptSig
|
935
|
+
# pushes onto the stack:
|
936
|
+
|
937
|
+
return 0 if @chunks.size == 0
|
938
|
+
|
939
|
+
data = nil
|
940
|
+
@chunks.each do |chunk|
|
941
|
+
case chunk
|
942
|
+
when Fixnum
|
943
|
+
data = ""
|
944
|
+
return 0 if chunk > OP_16
|
945
|
+
when String
|
946
|
+
data = chunk
|
947
|
+
end
|
948
|
+
end
|
949
|
+
return 0 if data == ""
|
950
|
+
|
951
|
+
::Bitcoin::Script.new(data).sigops_count_accurate(true)
|
952
|
+
end
|
953
|
+
|
954
|
+
# Converts OP_{0,1,2,...,16} into 0, 1, 2, ..., 16.
|
955
|
+
# Returns nil for other opcodes.
|
956
|
+
def self.decode_OP_N(opcode)
|
957
|
+
if opcode == OP_0
|
958
|
+
return 0
|
959
|
+
end
|
960
|
+
if opcode.is_a?(Fixnum) && opcode >= OP_1 && opcode <= OP_16
|
961
|
+
return opcode - (OP_1 - 1);
|
962
|
+
else
|
963
|
+
nil
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
|
968
|
+
|
969
|
+
|
970
|
+
## OPCODES
|
971
|
+
|
972
|
+
# Does nothing
|
973
|
+
def op_nop; end
|
974
|
+
def op_nop1; end
|
975
|
+
def op_nop2; end
|
976
|
+
def op_nop3; end
|
977
|
+
def op_nop4; end
|
978
|
+
def op_nop5; end
|
979
|
+
def op_nop6; end
|
980
|
+
def op_nop7; end
|
981
|
+
def op_nop8; end
|
982
|
+
def op_nop9; end
|
983
|
+
def op_nop10; end
|
984
|
+
|
985
|
+
# Duplicates the top stack item.
|
986
|
+
def op_dup
|
987
|
+
@stack << (@stack[-1].dup rescue @stack[-1])
|
988
|
+
end
|
989
|
+
|
990
|
+
# The input is hashed using SHA-256.
|
991
|
+
def op_sha256
|
992
|
+
buf = pop_string
|
993
|
+
@stack << Digest::SHA256.digest(buf)
|
994
|
+
end
|
995
|
+
|
996
|
+
# The input is hashed using SHA-1.
|
997
|
+
def op_sha1
|
998
|
+
buf = pop_string
|
999
|
+
@stack << Digest::SHA1.digest(buf)
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
# The input is hashed twice: first with SHA-256 and then with RIPEMD-160.
|
1003
|
+
def op_hash160
|
1004
|
+
buf = pop_string
|
1005
|
+
@stack << Digest::RMD160.digest(Digest::SHA256.digest(buf))
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
# The input is hashed using RIPEMD-160.
|
1009
|
+
def op_ripemd160
|
1010
|
+
buf = pop_string
|
1011
|
+
@stack << Digest::RMD160.digest(buf)
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
# The input is hashed two times with SHA-256.
|
1015
|
+
def op_hash256
|
1016
|
+
buf = pop_string
|
1017
|
+
@stack << Digest::SHA256.digest(Digest::SHA256.digest(buf))
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
# Puts the input onto the top of the alt stack. Removes it from the main stack.
|
1021
|
+
def op_toaltstack
|
1022
|
+
@stack_alt << @stack.pop
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
# Puts the input onto the top of the main stack. Removes it from the alt stack.
|
1026
|
+
def op_fromaltstack
|
1027
|
+
@stack << @stack_alt.pop
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
# The item at the top of the stack is copied and inserted before the second-to-top item.
|
1031
|
+
def op_tuck
|
1032
|
+
@stack[-2..-1] = [ @stack[-1], *@stack[-2..-1] ]
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
# The top two items on the stack are swapped.
|
1036
|
+
def op_swap
|
1037
|
+
@stack[-2..-1] = @stack[-2..-1].reverse if @stack[-2]
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
# If both a and b are not 0, the output is 1. Otherwise 0.
|
1041
|
+
def op_booland
|
1042
|
+
a, b = pop_int(2)
|
1043
|
+
@stack << (![a,b].any?{|n| n == 0 } ? 1 : 0)
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
# If a or b is not 0, the output is 1. Otherwise 0.
|
1047
|
+
def op_boolor
|
1048
|
+
a, b = pop_int(2)
|
1049
|
+
@stack << ( (a != 0 || b != 0) ? 1 : 0 )
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
# a is added to b.
|
1053
|
+
def op_add
|
1054
|
+
a, b = pop_int(2)
|
1055
|
+
@stack << a + b
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
# b is subtracted from a.
|
1059
|
+
def op_sub
|
1060
|
+
a, b = pop_int(2)
|
1061
|
+
@stack << a - b
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
# Returns 1 if a is less than b, 0 otherwise.
|
1065
|
+
def op_lessthan
|
1066
|
+
a, b = pop_int(2)
|
1067
|
+
@stack << (a < b ? 1 : 0)
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
# Returns 1 if a is less than or equal to b, 0 otherwise.
|
1071
|
+
def op_lessthanorequal
|
1072
|
+
a, b = pop_int(2)
|
1073
|
+
@stack << (a <= b ? 1 : 0)
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
# Returns 1 if a is greater than b, 0 otherwise.
|
1077
|
+
def op_greaterthan
|
1078
|
+
a, b = pop_int(2)
|
1079
|
+
@stack << (a > b ? 1 : 0)
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
# Returns 1 if a is greater than or equal to b, 0 otherwise.
|
1083
|
+
def op_greaterthanorequal
|
1084
|
+
a, b = pop_int(2)
|
1085
|
+
@stack << (a >= b ? 1 : 0)
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
# If the input is 0 or 1, it is flipped. Otherwise the output will be 0.
|
1089
|
+
def op_not
|
1090
|
+
a = pop_int
|
1091
|
+
@stack << (a == 0 ? 1 : 0)
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
def op_0notequal
|
1095
|
+
a = pop_int
|
1096
|
+
@stack << (a != 0 ? 1 : 0)
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
# The input is made positive.
|
1100
|
+
def op_abs
|
1101
|
+
a = pop_int
|
1102
|
+
@stack << a.abs
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
# The input is divided by 2. Currently disabled.
|
1106
|
+
def op_2div
|
1107
|
+
a = pop_int
|
1108
|
+
@stack << (a >> 1)
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
# The input is multiplied by 2. Currently disabled.
|
1112
|
+
def op_2mul
|
1113
|
+
a = pop_int
|
1114
|
+
@stack << (a << 1)
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
# 1 is added to the input.
|
1118
|
+
def op_1add
|
1119
|
+
a = pop_int
|
1120
|
+
@stack << (a + 1)
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
# 1 is subtracted from the input.
|
1124
|
+
def op_1sub
|
1125
|
+
a = pop_int
|
1126
|
+
@stack << (a - 1)
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
# The sign of the input is flipped.
|
1130
|
+
def op_negate
|
1131
|
+
a = pop_int
|
1132
|
+
@stack << -a
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
# Removes the top stack item.
|
1136
|
+
def op_drop
|
1137
|
+
@stack.pop
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
# Returns 1 if the inputs are exactly equal, 0 otherwise.
|
1141
|
+
def op_equal
|
1142
|
+
a, b = pop_string(2)
|
1143
|
+
@stack << (a == b ? 1 : 0)
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
# Marks transaction as invalid if top stack value is not true. True is removed, but false is not.
|
1147
|
+
def op_verify
|
1148
|
+
res = pop_int
|
1149
|
+
if cast_to_bool(res) == false
|
1150
|
+
@stack << res
|
1151
|
+
@script_invalid = true # raise 'transaction invalid' ?
|
1152
|
+
else
|
1153
|
+
@script_invalid = false
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
# Same as OP_EQUAL, but runs OP_VERIFY afterward.
|
1158
|
+
def op_equalverify
|
1159
|
+
op_equal; op_verify
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
# An empty array of bytes is pushed onto the stack.
|
1163
|
+
def op_0
|
1164
|
+
@stack << "" # []
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
# The number 1 is pushed onto the stack. Same as OP_TRUE
|
1168
|
+
def op_1
|
1169
|
+
@stack << 1
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
# Returns the smaller of a and b.
|
1173
|
+
def op_min
|
1174
|
+
@stack << pop_int(2).min
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
# Returns the larger of a and b.
|
1178
|
+
def op_max
|
1179
|
+
@stack << pop_int(2).max
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
# Copies the pair of items two spaces back in the stack to the front.
|
1183
|
+
def op_2over
|
1184
|
+
@stack << @stack[-4]
|
1185
|
+
@stack << @stack[-4]
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
# Swaps the top two pairs of items.
|
1189
|
+
def op_2swap
|
1190
|
+
p1 = @stack.pop(2)
|
1191
|
+
p2 = @stack.pop(2)
|
1192
|
+
@stack += p1 += p2
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
# If the input is true, duplicate it.
|
1196
|
+
def op_ifdup
|
1197
|
+
if cast_to_bool(@stack.last) == true
|
1198
|
+
@stack << @stack.last
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
# The number -1 is pushed onto the stack.
|
1203
|
+
def op_1negate
|
1204
|
+
@stack << -1
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
# Puts the number of stack items onto the stack.
|
1208
|
+
def op_depth
|
1209
|
+
@stack << @stack.size
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
# Returns 1 if x is within the specified range (left-inclusive), 0 otherwise.
|
1213
|
+
def op_within
|
1214
|
+
bn1, bn2, bn3 = pop_int(3)
|
1215
|
+
@stack << ( (bn2 <= bn1 && bn1 < bn3) ? 1 : 0 )
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
# Returns 1 if the numbers are equal, 0 otherwise.
|
1219
|
+
def op_numequal
|
1220
|
+
a, b = pop_int(2)
|
1221
|
+
@stack << (a == b ? 1 : 0)
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
# Returns 1 if the numbers are not equal, 0 otherwise.
|
1225
|
+
def op_numnotequal
|
1226
|
+
a, b = pop_int(2)
|
1227
|
+
@stack << (a != b ? 1 : 0)
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
# Marks transaction as invalid.
|
1231
|
+
def op_return
|
1232
|
+
@script_invalid = true; nil
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
# Copies the second-to-top stack item to the top.
|
1236
|
+
def op_over
|
1237
|
+
item = @stack[-2]
|
1238
|
+
@stack << item if item
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
# If the top stack value is not 0, the statements are executed. The top stack value is removed.
|
1242
|
+
def op_if
|
1243
|
+
value = false
|
1244
|
+
if @do_exec
|
1245
|
+
(invalid; return) if @stack.size < 1
|
1246
|
+
value = cast_to_bool(pop_string) == false ? false : true
|
1247
|
+
end
|
1248
|
+
@exec_stack << value
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
# If the top stack value is 0, the statements are executed. The top stack value is removed.
|
1252
|
+
def op_notif
|
1253
|
+
value = false
|
1254
|
+
if @do_exec
|
1255
|
+
(invalid; return) if @stack.size < 1
|
1256
|
+
value = cast_to_bool(pop_string) == false ? true : false
|
1257
|
+
end
|
1258
|
+
@exec_stack << value
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
# If the preceding OP_IF or OP_NOTIF or OP_ELSE was not executed then these statements are and if the preceding OP_IF or OP_NOTIF or OP_ELSE was executed then these statements are not.
|
1262
|
+
def op_else
|
1263
|
+
return if @exec_stack.empty?
|
1264
|
+
@exec_stack[-1] = !@exec_stack[-1]
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
# Ends an if/else block.
|
1268
|
+
def op_endif
|
1269
|
+
return if @exec_stack.empty?
|
1270
|
+
@exec_stack.pop
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
# The item n back in the stack is copied to the top.
|
1274
|
+
def op_pick
|
1275
|
+
return invalid if @stack.size < 2
|
1276
|
+
pos = pop_int
|
1277
|
+
return invalid if (pos < 0) || (pos >= @stack.size)
|
1278
|
+
item = @stack[-(pos+1)]
|
1279
|
+
@stack << item if item
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
# The fifth and sixth items back are moved to the top of the stack.
|
1283
|
+
def op_2rot
|
1284
|
+
return invalid if @stack.size < 6
|
1285
|
+
@stack[-6..-1] = [ *@stack[-4..-1], *@stack[-6..-5] ]
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
# The item n back in the stack is moved to the top.
|
1289
|
+
def op_roll
|
1290
|
+
return invalid if @stack.size < 2
|
1291
|
+
pos = pop_int
|
1292
|
+
return invalid if (pos < 0) || (pos >= @stack.size)
|
1293
|
+
idx = -(pos+1)
|
1294
|
+
item = @stack[idx]
|
1295
|
+
if item
|
1296
|
+
@stack.delete_at(idx)
|
1297
|
+
@stack << item if item
|
1298
|
+
end
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
# The top three items on the stack are rotated to the left.
|
1302
|
+
def op_rot
|
1303
|
+
return if @stack.size < 3
|
1304
|
+
@stack[-3..-1] = [ @stack[-2], @stack[-1], @stack[-3] ]
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
# Removes the top two stack items.
|
1308
|
+
def op_2drop
|
1309
|
+
@stack.pop(2)
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
# Duplicates the top two stack items.
|
1313
|
+
def op_2dup
|
1314
|
+
@stack.push(*@stack[-2..-1])
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
# Duplicates the top three stack items.
|
1318
|
+
def op_3dup
|
1319
|
+
@stack.push(*@stack[-3..-1])
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
# Removes the second-to-top stack item.
|
1323
|
+
def op_nip
|
1324
|
+
@stack.delete_at(-2)
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
# Returns the length of the input string.
|
1328
|
+
def op_size
|
1329
|
+
item = @stack[-1]
|
1330
|
+
size = case item
|
1331
|
+
when String; item.bytesize
|
1332
|
+
when Numeric; OpenSSL::BN.new(item.to_s).to_mpi.size - 4
|
1333
|
+
end
|
1334
|
+
@stack << size
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
# Transaction is invalid unless occuring in an unexecuted OP_IF branch
|
1338
|
+
def op_ver
|
1339
|
+
invalid if @do_exec
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
def pop_int(count=nil)
|
1343
|
+
return cast_to_bignum(@stack.pop) unless count
|
1344
|
+
@stack.pop(count).map{|i| cast_to_bignum(i) }
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
def pop_string(count=nil)
|
1348
|
+
return cast_to_string(@stack.pop) unless count
|
1349
|
+
@stack.pop(count).map{|i| cast_to_string(i) }
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
def cast_to_bignum(buf)
|
1353
|
+
return (invalid; 0) unless buf
|
1354
|
+
case buf
|
1355
|
+
when Numeric
|
1356
|
+
invalid if OpenSSL::BN.new(buf.to_s).to_s(0).unpack("N")[0] > 4
|
1357
|
+
buf
|
1358
|
+
when String
|
1359
|
+
invalid if buf.bytesize > 4
|
1360
|
+
OpenSSL::BN.new([buf.bytesize].pack("N") + buf.reverse, 0).to_i
|
1361
|
+
else; raise TypeError, 'cast_to_bignum: failed to cast: %s (%s)' % [buf, buf.class]
|
1362
|
+
end
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
def cast_to_string(buf)
|
1366
|
+
return (invalid; "") unless buf
|
1367
|
+
case buf
|
1368
|
+
when Numeric; OpenSSL::BN.new(buf.to_s).to_s(0)[4..-1].reverse
|
1369
|
+
when String; buf;
|
1370
|
+
else; raise TypeError, 'cast_to_string: failed to cast: %s (%s)' % [buf, buf.class]
|
1371
|
+
end
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
def cast_to_bool(buf)
|
1375
|
+
buf = cast_to_string(buf).unpack("C*")
|
1376
|
+
size = buf.size
|
1377
|
+
buf.each.with_index{|byte,index|
|
1378
|
+
if byte != 0
|
1379
|
+
# Can be negative zero
|
1380
|
+
if (index == (size-1)) && byte == 0x80
|
1381
|
+
return false
|
1382
|
+
else
|
1383
|
+
return true
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
}
|
1387
|
+
return false
|
1388
|
+
end
|
1389
|
+
|
1390
|
+
# Same as OP_NUMEQUAL, but runs OP_VERIFY afterward.
|
1391
|
+
def op_numequalverify
|
1392
|
+
op_numequal; op_verify
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
# All of the signature checking words will only match signatures
|
1396
|
+
# to the data after the most recently-executed OP_CODESEPARATOR.
|
1397
|
+
def op_codeseparator
|
1398
|
+
@codehash_start = @chunks.size - @chunks.reverse.index(OP_CODESEPARATOR)
|
1399
|
+
@last_codeseparator_index = @chunk_last_index
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
def codehash_script(opcode)
|
1403
|
+
# CScript scriptCode(pbegincodehash, pend);
|
1404
|
+
script = to_string(@chunks[(@codehash_start||0)...@chunks.size-@chunks.reverse.index(opcode)])
|
1405
|
+
checkhash = Bitcoin.hash160(Bitcoin::Script.binary_from_string(script).unpack("H*")[0])
|
1406
|
+
[script, checkhash]
|
1407
|
+
end
|
1408
|
+
|
1409
|
+
|
1410
|
+
# do a CHECKSIG operation on the current stack,
|
1411
|
+
# asking +check_callback+ to do the actual signature verification.
|
1412
|
+
# This is used by Protocol::Tx#verify_input_signature
|
1413
|
+
def op_checksig(check_callback, opts={})
|
1414
|
+
return invalid if @stack.size < 2
|
1415
|
+
pubkey = cast_to_string(@stack.pop)
|
1416
|
+
return (@stack << 0) unless Bitcoin::Script.check_pubkey_encoding?(pubkey, opts)
|
1417
|
+
drop_sigs = [ cast_to_string(@stack[-1]) ]
|
1418
|
+
|
1419
|
+
signature = cast_to_string(@stack.pop)
|
1420
|
+
return invalid unless Bitcoin::Script.check_signature_encoding?(signature, opts)
|
1421
|
+
return (@stack << 0) if signature == ""
|
1422
|
+
|
1423
|
+
sig, hash_type = parse_sig(signature)
|
1424
|
+
|
1425
|
+
subscript = sighash_subscript(drop_sigs, opts)
|
1426
|
+
|
1427
|
+
if check_callback == nil # for tests
|
1428
|
+
@stack << 1
|
1429
|
+
else # real signature check callback
|
1430
|
+
@stack <<
|
1431
|
+
((check_callback.call(pubkey, sig, hash_type, subscript) == true) ? 1 : 0)
|
1432
|
+
end
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
def sighash_subscript(drop_sigs, opts = {})
|
1436
|
+
if opts[:fork_id]
|
1437
|
+
drop_sigs.reject! do |signature|
|
1438
|
+
if signature && signature.size > 0
|
1439
|
+
_, hash_type = parse_sig(signature)
|
1440
|
+
(hash_type&SIGHASH_TYPE[:forkid]) != 0
|
1441
|
+
end
|
1442
|
+
end
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
if inner_p2sh? && @inner_script_code
|
1446
|
+
::Bitcoin::Script.new(@inner_script_code).to_binary_without_signatures(drop_sigs)
|
1447
|
+
else
|
1448
|
+
to_binary_without_signatures(drop_sigs)
|
1449
|
+
end
|
1450
|
+
end
|
1451
|
+
|
1452
|
+
# Same as OP_CHECKSIG, but OP_VERIFY is executed afterward.
|
1453
|
+
def op_checksigverify(check_callback, opts={})
|
1454
|
+
op_checksig(check_callback, opts)
|
1455
|
+
op_verify
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
# do a CHECKMULTISIG operation on the current stack,
|
1459
|
+
# asking +check_callback+ to do the actual signature verification.
|
1460
|
+
#
|
1461
|
+
# CHECKMULTISIG does a m-of-n signatures verification on scripts of the form:
|
1462
|
+
# 0 <sig1> <sig2> | 2 <pub1> <pub2> 2 OP_CHECKMULTISIG
|
1463
|
+
# 0 <sig1> <sig2> | 2 <pub1> <pub2> <pub3> 3 OP_CHECKMULTISIG
|
1464
|
+
# 0 <sig1> <sig2> <sig3> | 3 <pub1> <pub2> <pub3> 3 OP_CHECKMULTISIG
|
1465
|
+
#
|
1466
|
+
# see https://en.bitcoin.it/wiki/BIP_0011 for details.
|
1467
|
+
# see https://github.com/bitcoin/bitcoin/blob/master/src/script.cpp#L931
|
1468
|
+
#
|
1469
|
+
# TODO: validate signature order
|
1470
|
+
# TODO: take global opcode count
|
1471
|
+
def op_checkmultisig(check_callback, opts={})
|
1472
|
+
return invalid if @stack.size < 1
|
1473
|
+
n_pubkeys = pop_int
|
1474
|
+
return invalid unless (0..20).include?(n_pubkeys)
|
1475
|
+
#return invalid if (nOpCount += n_pubkeys) > 201
|
1476
|
+
return invalid if @stack.size < n_pubkeys
|
1477
|
+
pubkeys = pop_string(n_pubkeys)
|
1478
|
+
|
1479
|
+
return invalid if @stack.size < 1
|
1480
|
+
n_sigs = pop_int
|
1481
|
+
return invalid if n_sigs < 0 || n_sigs > n_pubkeys
|
1482
|
+
return invalid if @stack.size < n_sigs
|
1483
|
+
sigs = pop_string(n_sigs)
|
1484
|
+
drop_sigs = sigs.dup
|
1485
|
+
|
1486
|
+
# Bitcoin-core removes an extra item from the stack
|
1487
|
+
@stack.pop
|
1488
|
+
|
1489
|
+
subscript = sighash_subscript(drop_sigs, opts)
|
1490
|
+
|
1491
|
+
success = true
|
1492
|
+
while success && n_sigs > 0
|
1493
|
+
sig, pub = sigs.pop, pubkeys.pop
|
1494
|
+
return (@stack << 0) unless Bitcoin::Script.check_pubkey_encoding?(pub, opts)
|
1495
|
+
return invalid unless Bitcoin::Script.check_signature_encoding?(sig, opts)
|
1496
|
+
unless sig && sig.size > 0
|
1497
|
+
success = false
|
1498
|
+
break
|
1499
|
+
end
|
1500
|
+
signature, hash_type = parse_sig(sig)
|
1501
|
+
if pub.size > 0 && check_callback.call(pub, signature, hash_type, subscript)
|
1502
|
+
n_sigs -= 1
|
1503
|
+
else
|
1504
|
+
sigs << sig
|
1505
|
+
end
|
1506
|
+
n_pubkeys -= 1
|
1507
|
+
success = false if n_sigs > n_pubkeys
|
1508
|
+
end
|
1509
|
+
|
1510
|
+
@stack << (success ? 1 : 0)
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
# Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward.
|
1514
|
+
def op_checkmultisigverify(check_callback, opts={})
|
1515
|
+
op_checkmultisig(check_callback, opts)
|
1516
|
+
op_verify
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
# op_eval: https://en.bitcoin.it/wiki/BIP_0012
|
1520
|
+
# the BIP was never accepted and must be handled as old OP_NOP1
|
1521
|
+
def op_nop1
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
OPCODES_METHOD = Hash[*instance_methods.grep(/^op_/).map{|m|
|
1525
|
+
[ (OPCODES.find{|k,v| v == m.to_s.upcase }.first rescue nil), m ]
|
1526
|
+
}.flatten]
|
1527
|
+
OPCODES_METHOD[0] = :op_0
|
1528
|
+
OPCODES_METHOD[81] = :op_1
|
1529
|
+
|
1530
|
+
def self.check_pubkey_encoding?(pubkey, opts={})
|
1531
|
+
return false if opts[:verify_strictenc] && !is_compressed_or_uncompressed_pub_key?(pubkey)
|
1532
|
+
true
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
def self.is_compressed_or_uncompressed_pub_key?(pubkey)
|
1536
|
+
return false if pubkey.bytesize < 33 # "Non-canonical public key: too short"
|
1537
|
+
case pubkey[0]
|
1538
|
+
when "\x04"
|
1539
|
+
return false if pubkey.bytesize != 65 # "Non-canonical public key: invalid length for uncompressed key"
|
1540
|
+
when "\x02", "\x03"
|
1541
|
+
return false if pubkey.bytesize != 33 # "Non-canonical public key: invalid length for compressed key"
|
1542
|
+
else
|
1543
|
+
return false # "Non-canonical public key: compressed nor uncompressed"
|
1544
|
+
end
|
1545
|
+
true
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
# Loosely matches CheckSignatureEncoding()
|
1549
|
+
def self.check_signature_encoding?(sig, opts={})
|
1550
|
+
return true if sig.bytesize == 0
|
1551
|
+
return false if (opts[:verify_dersig] || opts[:verify_low_s] || opts[:verify_strictenc]) and !is_der_signature?(sig)
|
1552
|
+
return false if opts[:verify_low_s] && !is_low_der_signature?(sig)
|
1553
|
+
|
1554
|
+
if opts[:verify_strictenc]
|
1555
|
+
return false unless is_defined_hashtype_signature?(sig)
|
1556
|
+
|
1557
|
+
hash_type = sig.unpack('C*')[-1]
|
1558
|
+
uses_forkid = (hash_type&SIGHASH_TYPE[:forkid]) != 0
|
1559
|
+
return false if opts[:fork_id] && !uses_forkid
|
1560
|
+
return false if !opts[:fork_id] && uses_forkid
|
1561
|
+
end
|
1562
|
+
|
1563
|
+
true
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
# Loosely correlates with IsDERSignature() from interpreter.cpp
|
1567
|
+
def self.is_der_signature?(sig)
|
1568
|
+
return false if sig.bytesize < 9 # Non-canonical signature: too short
|
1569
|
+
return false if sig.bytesize > 73 # Non-canonical signature: too long
|
1570
|
+
|
1571
|
+
s = sig.unpack("C*")
|
1572
|
+
|
1573
|
+
return false if s[0] != 0x30 # Non-canonical signature: wrong type
|
1574
|
+
return false if s[1] != s.size-3 # Non-canonical signature: wrong length marker
|
1575
|
+
|
1576
|
+
length_r = s[3]
|
1577
|
+
return false if (5 + length_r) >= s.size # Non-canonical signature: S length misplaced
|
1578
|
+
length_s = s[5+length_r]
|
1579
|
+
return false if (length_r + length_s + 7) != s.size # Non-canonical signature: R+S length mismatch
|
1580
|
+
|
1581
|
+
return false if s[2] != 0x02 # Non-canonical signature: R value type mismatch
|
1582
|
+
|
1583
|
+
return false if length_r == 0 # Non-canonical signature: R length is zero
|
1584
|
+
|
1585
|
+
r_val = s.slice(4, length_r)
|
1586
|
+
return false if r_val[0] & 0x80 != 0 # Non-canonical signature: R value negative
|
1587
|
+
|
1588
|
+
return false if length_r > 1 && (r_val[0] == 0x00) && !(r_val[1] & 0x80 != 0) # Non-canonical signature: R value excessively padded
|
1589
|
+
|
1590
|
+
s_val = s.slice(6 + length_r, length_s)
|
1591
|
+
return false if s[6 + length_r - 2] != 0x02 # Non-canonical signature: S value type mismatch
|
1592
|
+
|
1593
|
+
return false if length_s == 0 # Non-canonical signature: S length is zero
|
1594
|
+
return false if (s_val[0] & 0x80) != 0 # Non-canonical signature: S value negative
|
1595
|
+
|
1596
|
+
return false if length_s > 1 && (s_val[0] == 0x00) && !(s_val[1] & 0x80) # Non-canonical signature: S value excessively padded
|
1597
|
+
|
1598
|
+
true
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
# Compares two arrays of bytes
|
1602
|
+
def self.compare_big_endian(c1, c2)
|
1603
|
+
c1, c2 = c1.dup, c2.dup # Clone the arrays
|
1604
|
+
|
1605
|
+
while c1.size > c2.size
|
1606
|
+
return 1 if c1.shift > 0
|
1607
|
+
end
|
1608
|
+
|
1609
|
+
while c2.size > c1.size
|
1610
|
+
return -1 if c2.shift > 0
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
c1.size.times{|idx| return c1[idx] - c2[idx] if c1[idx] != c2[idx] }
|
1614
|
+
0
|
1615
|
+
end
|
1616
|
+
|
1617
|
+
# Loosely correlates with IsLowDERSignature() from interpreter.cpp
|
1618
|
+
def self.is_low_der_signature?(sig)
|
1619
|
+
s = sig.unpack("C*")
|
1620
|
+
|
1621
|
+
length_r = s[3]
|
1622
|
+
length_s = s[5+length_r]
|
1623
|
+
s_val = s.slice(6 + length_r, length_s)
|
1624
|
+
|
1625
|
+
# If the S value is above the order of the curve divided by two, its
|
1626
|
+
# complement modulo the order could have been used instead, which is
|
1627
|
+
# one byte shorter when encoded correctly.
|
1628
|
+
max_mod_half_order = [
|
1629
|
+
0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
1630
|
+
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
1631
|
+
0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,
|
1632
|
+
0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0]
|
1633
|
+
|
1634
|
+
compare_big_endian(s_val, [0]) > 0 &&
|
1635
|
+
compare_big_endian(s_val, max_mod_half_order) <= 0
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
def self.is_defined_hashtype_signature?(sig)
|
1639
|
+
return false if sig.empty?
|
1640
|
+
|
1641
|
+
s = sig.unpack("C*")
|
1642
|
+
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay] | SIGHASH_TYPE[:forkid]))
|
1643
|
+
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single] # Non-canonical signature: unknown hashtype byte
|
1644
|
+
|
1645
|
+
true
|
1646
|
+
end
|
1647
|
+
|
1648
|
+
|
1649
|
+
private
|
1650
|
+
|
1651
|
+
def parse_sig(sig)
|
1652
|
+
hash_type = sig[-1].unpack("C")[0]
|
1653
|
+
sig = sig[0...-1]
|
1654
|
+
return sig, hash_type
|
1655
|
+
end
|
1656
|
+
end
|