bitcoin-ruby 0.0.6 → 0.0.7
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/.gitignore +0 -1
- data/.travis.yml +2 -7
- data/COPYING +1 -1
- data/Gemfile +2 -6
- data/Gemfile.lock +34 -0
- data/README.rdoc +16 -68
- data/Rakefile +3 -6
- data/bin/bitcoin_shell +0 -1
- data/{concept-examples/blockchain-pow.rb → examples/concept-blockchain-pow.rb} +0 -0
- data/lib/bitcoin.rb +350 -296
- data/lib/bitcoin/builder.rb +3 -1
- data/lib/bitcoin/connection.rb +2 -1
- data/lib/bitcoin/contracthash.rb +76 -0
- data/lib/bitcoin/dogecoin.rb +97 -0
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +74 -0
- data/lib/bitcoin/ffi/openssl.rb +98 -2
- data/lib/bitcoin/ffi/secp256k1.rb +144 -0
- data/lib/bitcoin/key.rb +12 -2
- data/lib/bitcoin/logger.rb +3 -12
- data/lib/bitcoin/protocol/block.rb +3 -9
- data/lib/bitcoin/protocol/parser.rb +6 -2
- data/lib/bitcoin/protocol/tx.rb +44 -13
- data/lib/bitcoin/protocol/txin.rb +4 -2
- data/lib/bitcoin/protocol/txout.rb +2 -2
- data/lib/bitcoin/script.rb +212 -37
- data/lib/bitcoin/trezor/mnemonic.rb +130 -0
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bitcoin_spec.rb +32 -3
- data/spec/bitcoin/builder_spec.rb +18 -0
- data/spec/bitcoin/contracthash_spec.rb +45 -0
- data/spec/bitcoin/dogecoin_spec.rb +176 -0
- data/spec/bitcoin/ffi_openssl.rb +45 -0
- data/spec/bitcoin/fixtures/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +24 -0
- data/spec/bitcoin/fixtures/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +24 -0
- data/spec/bitcoin/fixtures/coinbase-toshi.json +33 -0
- data/spec/bitcoin/fixtures/coinbase.json +24 -0
- data/spec/bitcoin/fixtures/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-01-toshi.json +46 -0
- data/spec/bitcoin/fixtures/rawtx-02-toshi.json +46 -0
- data/spec/bitcoin/fixtures/rawtx-03-toshi.json +73 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
- data/spec/bitcoin/protocol/block_spec.rb +0 -22
- data/spec/bitcoin/protocol/tx_spec.rb +145 -2
- data/spec/bitcoin/script/script_spec.rb +282 -0
- data/spec/bitcoin/secp256k1_spec.rb +48 -0
- data/spec/bitcoin/spec_helper.rb +0 -51
- data/spec/bitcoin/trezor/mnemonic_spec.rb +161 -0
- metadata +48 -98
- data/bin/bitcoin_dns_seed +0 -130
- data/bin/bitcoin_gui +0 -80
- data/bin/bitcoin_node +0 -153
- data/bin/bitcoin_node_cli +0 -81
- data/bin/bitcoin_wallet +0 -402
- data/doc/CONFIG.rdoc +0 -66
- data/doc/EXAMPLES.rdoc +0 -13
- data/doc/NAMECOIN.rdoc +0 -34
- data/doc/NODE.rdoc +0 -225
- data/doc/STORAGE.rdoc +0 -33
- data/doc/WALLET.rdoc +0 -102
- data/examples/balance.rb +0 -66
- data/examples/forwarder.rb +0 -73
- data/examples/index_nhash.rb +0 -24
- data/examples/reindex_p2sh_addrs.rb +0 -44
- data/examples/relay_tx.rb +0 -22
- data/examples/verify_tx.rb +0 -57
- data/lib/bitcoin/config.rb +0 -58
- data/lib/bitcoin/gui/addr_view.rb +0 -44
- data/lib/bitcoin/gui/bitcoin-ruby.png +0 -0
- data/lib/bitcoin/gui/bitcoin-ruby.svg +0 -80
- data/lib/bitcoin/gui/conn_view.rb +0 -38
- data/lib/bitcoin/gui/connection.rb +0 -70
- data/lib/bitcoin/gui/em_gtk.rb +0 -30
- data/lib/bitcoin/gui/gui.builder +0 -1643
- data/lib/bitcoin/gui/gui.rb +0 -292
- data/lib/bitcoin/gui/helpers.rb +0 -115
- data/lib/bitcoin/gui/tree_view.rb +0 -84
- data/lib/bitcoin/gui/tx_view.rb +0 -69
- data/lib/bitcoin/namecoin.rb +0 -280
- data/lib/bitcoin/network/command_client.rb +0 -104
- data/lib/bitcoin/network/command_handler.rb +0 -570
- data/lib/bitcoin/network/connection_handler.rb +0 -387
- data/lib/bitcoin/network/node.rb +0 -565
- data/lib/bitcoin/storage/dummy/dummy_store.rb +0 -179
- data/lib/bitcoin/storage/models.rb +0 -171
- data/lib/bitcoin/storage/sequel/migrations.rb +0 -99
- data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +0 -52
- data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +0 -45
- data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +0 -18
- data/lib/bitcoin/storage/sequel/migrations/004_change_txin_prev_out_to_blob.rb +0 -18
- data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +0 -14
- data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +0 -31
- data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +0 -16
- data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +0 -31
- data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +0 -56
- data/lib/bitcoin/storage/sequel/sequel_store.rb +0 -551
- data/lib/bitcoin/storage/storage.rb +0 -517
- data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +0 -52
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +0 -18
- data/lib/bitcoin/storage/utxo/migrations/003_update_indices.rb +0 -14
- data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +0 -14
- data/lib/bitcoin/storage/utxo/utxo_store.rb +0 -374
- data/lib/bitcoin/validation.rb +0 -400
- data/lib/bitcoin/wallet/coinselector.rb +0 -33
- data/lib/bitcoin/wallet/keygenerator.rb +0 -77
- data/lib/bitcoin/wallet/keystore.rb +0 -207
- data/lib/bitcoin/wallet/txdp.rb +0 -118
- data/lib/bitcoin/wallet/wallet.rb +0 -281
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +0 -43
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +0 -67
- data/spec/bitcoin/namecoin_spec.rb +0 -182
- data/spec/bitcoin/node/command_api_spec.rb +0 -663
- data/spec/bitcoin/storage/models_spec.rb +0 -104
- data/spec/bitcoin/storage/reorg_spec.rb +0 -236
- data/spec/bitcoin/storage/storage_spec.rb +0 -387
- data/spec/bitcoin/storage/validation_spec.rb +0 -300
- data/spec/bitcoin/wallet/coinselector_spec.rb +0 -38
- data/spec/bitcoin/wallet/keygenerator_spec.rb +0 -69
- data/spec/bitcoin/wallet/keystore_spec.rb +0 -190
- data/spec/bitcoin/wallet/txdp_spec.rb +0 -76
- data/spec/bitcoin/wallet/wallet_spec.rb +0 -238
data/lib/bitcoin/key.rb
CHANGED
|
@@ -98,7 +98,12 @@ module Bitcoin
|
|
|
98
98
|
# key1 = Bitcoin::Key.generate
|
|
99
99
|
# sig = key1.sign("some data")
|
|
100
100
|
def sign(data)
|
|
101
|
-
@key.dsa_sign_asn1(data)
|
|
101
|
+
sig = @key.dsa_sign_asn1(data)
|
|
102
|
+
if Script::is_low_der_signature?(sig)
|
|
103
|
+
sig
|
|
104
|
+
else
|
|
105
|
+
Bitcoin::OpenSSL_EC.signature_to_low_s(sig)
|
|
106
|
+
end
|
|
102
107
|
end
|
|
103
108
|
|
|
104
109
|
# Verify signature +sig+ for +data+.
|
|
@@ -106,7 +111,12 @@ module Bitcoin
|
|
|
106
111
|
# key2.verify("some data", sig)
|
|
107
112
|
def verify(data, sig)
|
|
108
113
|
regenerate_pubkey unless @key.public_key
|
|
109
|
-
|
|
114
|
+
sig = Bitcoin::OpenSSL_EC.repack_der_signature(sig)
|
|
115
|
+
if sig
|
|
116
|
+
@key.dsa_verify_asn1(data, sig)
|
|
117
|
+
else
|
|
118
|
+
false
|
|
119
|
+
end
|
|
110
120
|
end
|
|
111
121
|
|
|
112
122
|
|
data/lib/bitcoin/logger.rb
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def level= l = 0
|
|
7
|
-
_level = l.is_a?(Fixnum) ? l : Log4r::LNAMES.index(l.to_s.upcase)
|
|
8
|
-
Log4r::Log4rTools.validate_level(_level)
|
|
9
|
-
@level = _level
|
|
10
|
-
LoggerFactory.define_methods(self)
|
|
11
|
-
Log4r::Logger.log_internal {"Logger '#{@fullname}' set to #{LNAMES[@level]}"}
|
|
12
|
-
@level
|
|
13
|
-
end
|
|
14
|
-
end
|
|
3
|
+
begin
|
|
4
|
+
require 'log4r'
|
|
5
|
+
rescue LoadError
|
|
15
6
|
end
|
|
16
7
|
|
|
17
8
|
module Bitcoin
|
|
@@ -56,7 +56,7 @@ module Bitcoin
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
# create block from raw binary +data+
|
|
59
|
-
def initialize(data)
|
|
59
|
+
def initialize(data=nil)
|
|
60
60
|
@tx = []
|
|
61
61
|
parse_data_from_io(data) if data
|
|
62
62
|
end
|
|
@@ -73,7 +73,7 @@ module Bitcoin
|
|
|
73
73
|
@ver, @prev_block, @mrkl_root, @time, @bits, @nonce = buf.read(80).unpack("Va32a32VVV")
|
|
74
74
|
recalc_block_hash
|
|
75
75
|
|
|
76
|
-
if Bitcoin.network[:
|
|
76
|
+
if Bitcoin.network[:auxpow_chain_id] != nil && (@ver & BLOCK_VERSION_AUXPOW) > 0
|
|
77
77
|
@aux_pow = AuxPow.new(nil)
|
|
78
78
|
@aux_pow.parse_data_from_io(buf)
|
|
79
79
|
end
|
|
@@ -197,7 +197,7 @@ module Bitcoin
|
|
|
197
197
|
end
|
|
198
198
|
@aux_pow = AuxPow.from_hash(h['aux_pow']) if h['aux_pow']
|
|
199
199
|
h['tx'].each{|tx| @tx << Tx.from_hash(tx) }
|
|
200
|
-
if h['tx'].any?
|
|
200
|
+
if h['tx'].any?
|
|
201
201
|
(raise "Block merkle root mismatch! Block: #{h['hash']}" unless verify_mrkl_root) if do_raise
|
|
202
202
|
end
|
|
203
203
|
}
|
|
@@ -231,12 +231,6 @@ module Bitcoin
|
|
|
231
231
|
# read json block from a file
|
|
232
232
|
def self.from_json_file(path); from_json( Bitcoin::Protocol.read_binary_file(path) ); end
|
|
233
233
|
|
|
234
|
-
# Get a Bitcoin::Validation object to validate this block. It needs a +store+
|
|
235
|
-
# to validate against, and optionally takes the +prev_block+ for optimization.
|
|
236
|
-
def validator(store, prev_block = nil)
|
|
237
|
-
@validator ||= Bitcoin::Validation::Block.new(self, store, prev_block)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
234
|
# get the (statistical) amount of work that was needed to generate this block.
|
|
241
235
|
def block_work
|
|
242
236
|
target = Bitcoin.decode_compact_bits(@bits).to_i(16)
|
|
@@ -23,7 +23,7 @@ module Bitcoin
|
|
|
23
23
|
#
|
|
24
24
|
def parse_inv(payload, type=:put)
|
|
25
25
|
count, payload = Protocol.unpack_var_int(payload)
|
|
26
|
-
payload.each_byte.each_slice(36){|i|
|
|
26
|
+
payload.each_byte.each_slice(36).with_index{|i, idx|
|
|
27
27
|
hash = i[4..-1].reverse.pack("C32")
|
|
28
28
|
case i[0]
|
|
29
29
|
when 1
|
|
@@ -34,7 +34,11 @@ module Bitcoin
|
|
|
34
34
|
end
|
|
35
35
|
when 2
|
|
36
36
|
if type == :put
|
|
37
|
-
@h.
|
|
37
|
+
if @h.respond_to?(:on_inv_block_v2)
|
|
38
|
+
@h.on_inv_block_v2(hash, idx, count)
|
|
39
|
+
else
|
|
40
|
+
@h.on_inv_block(hash)
|
|
41
|
+
end
|
|
38
42
|
else
|
|
39
43
|
@h.on_get_block(hash)
|
|
40
44
|
end
|
data/lib/bitcoin/protocol/tx.rb
CHANGED
|
@@ -44,6 +44,7 @@ module Bitcoin
|
|
|
44
44
|
# create tx from raw binary +data+
|
|
45
45
|
def initialize(data=nil)
|
|
46
46
|
@ver, @lock_time, @in, @out, @scripts = 1, 0, [], [], []
|
|
47
|
+
@enable_bitcoinconsensus = !!ENV['USE_BITCOINCONSENSUS']
|
|
47
48
|
parse_data_from_io(data) if data
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -160,7 +161,13 @@ module Bitcoin
|
|
|
160
161
|
# verify input signature +in_idx+ against the corresponding
|
|
161
162
|
# output in +outpoint_tx+
|
|
162
163
|
# outpoint
|
|
163
|
-
|
|
164
|
+
#
|
|
165
|
+
# options are: verify_sigpushonly, verify_minimaldata, verify_cleanstack, verify_dersig, verify_low_s, verify_strictenc
|
|
166
|
+
def verify_input_signature(in_idx, outpoint_tx_or_script, block_timestamp=Time.now.to_i, opts={})
|
|
167
|
+
if @enable_bitcoinconsensus
|
|
168
|
+
return bitcoinconsensus_verify_script(in_idx, outpoint_tx_or_script, block_timestamp, opts)
|
|
169
|
+
end
|
|
170
|
+
|
|
164
171
|
outpoint_idx = @in[in_idx].prev_out_index
|
|
165
172
|
script_sig = @in[in_idx].script_sig
|
|
166
173
|
|
|
@@ -173,10 +180,39 @@ module Bitcoin
|
|
|
173
180
|
end
|
|
174
181
|
|
|
175
182
|
@scripts[in_idx] = Bitcoin::Script.new(script_sig, script_pubkey)
|
|
176
|
-
|
|
183
|
+
return false if opts[:verify_sigpushonly] && !@scripts[in_idx].is_push_only?(script_sig)
|
|
184
|
+
return false if opts[:verify_minimaldata] && !@scripts[in_idx].pushes_are_canonical?
|
|
185
|
+
sig_valid = @scripts[in_idx].run(block_timestamp, opts) do |pubkey,sig,hash_type,subscript|
|
|
177
186
|
hash = signature_hash_for_input(in_idx, subscript, hash_type)
|
|
178
187
|
Bitcoin.verify_signature( hash, sig, pubkey.unpack("H*")[0] )
|
|
179
188
|
end
|
|
189
|
+
# BIP62 rule #6
|
|
190
|
+
return false if opts[:verify_cleanstack] && !@scripts[in_idx].stack.empty?
|
|
191
|
+
|
|
192
|
+
return sig_valid
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def bitcoinconsensus_verify_script(in_idx, outpoint_tx_or_script, block_timestamp=Time.now.to_i, opts={})
|
|
196
|
+
raise "Bitcoin::BitcoinConsensus shared library not found" unless Bitcoin::BitcoinConsensus.lib_available?
|
|
197
|
+
|
|
198
|
+
# If given an entire previous transaction, take the script from it
|
|
199
|
+
script_pubkey = if outpoint_tx_or_script.respond_to?(:out)
|
|
200
|
+
outpoint_idx = @in[in_idx].prev_out_index
|
|
201
|
+
outpoint_tx_or_script.out[outpoint_idx].pk_script
|
|
202
|
+
else
|
|
203
|
+
# Otherwise, it's already a script.
|
|
204
|
+
outpoint_tx_or_script
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
flags = Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_NONE
|
|
208
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_P2SH if block_timestamp >= 1333238400
|
|
209
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_SIGPUSHONLY if opts[:verify_sigpushonly]
|
|
210
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_MINIMALDATA if opts[:verify_minimaldata]
|
|
211
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_CLEANSTACK if opts[:verify_cleanstack]
|
|
212
|
+
flags |= Bitcoin::BitcoinConsensus::SCRIPT_VERIFY_LOW_S if opts[:verify_low_s]
|
|
213
|
+
|
|
214
|
+
payload ||= to_payload
|
|
215
|
+
Bitcoin::BitcoinConsensus.verify_script(in_idx, script_pubkey, payload, flags)
|
|
180
216
|
end
|
|
181
217
|
|
|
182
218
|
# convert to ruby hash (see also #from_hash)
|
|
@@ -206,9 +242,11 @@ module Bitcoin
|
|
|
206
242
|
# parse ruby hash (see also #to_hash)
|
|
207
243
|
def self.from_hash(h)
|
|
208
244
|
tx = new(nil)
|
|
209
|
-
tx.ver, tx.lock_time =
|
|
210
|
-
h['in']
|
|
211
|
-
h['out']
|
|
245
|
+
tx.ver, tx.lock_time = (h['ver'] || h['version']), h['lock_time']
|
|
246
|
+
ins = h['in'] || h['inputs']
|
|
247
|
+
outs = h['out'] || h['outputs']
|
|
248
|
+
ins .each{|input| tx.add_in TxIn.from_hash(input) }
|
|
249
|
+
outs.each{|output| tx.add_out TxOut.from_hash(output) }
|
|
212
250
|
tx.instance_eval{ @hash = hash_from_payload(@payload = to_payload) }
|
|
213
251
|
tx
|
|
214
252
|
end
|
|
@@ -228,13 +266,6 @@ module Bitcoin
|
|
|
228
266
|
# read json block from a file
|
|
229
267
|
def self.from_json_file(path); from_json( Bitcoin::Protocol.read_binary_file(path) ); end
|
|
230
268
|
|
|
231
|
-
# Get a Bitcoin::Validation object to validate this block. It needs a +store+
|
|
232
|
-
# to validate against, a block to validate tx chains inside one block, and
|
|
233
|
-
# optionally takes the +block_validator+ as an optimization.
|
|
234
|
-
def validator(store, block = nil, block_validator = nil)
|
|
235
|
-
@validator ||= Bitcoin::Validation::Tx.new(self, store, block, block_validator)
|
|
236
|
-
end
|
|
237
|
-
|
|
238
269
|
def size
|
|
239
270
|
payload.bytesize
|
|
240
271
|
end
|
|
@@ -316,7 +347,7 @@ module Bitcoin
|
|
|
316
347
|
end
|
|
317
348
|
|
|
318
349
|
def normalized_hash
|
|
319
|
-
signature_hash_for_input(-1, nil, SIGHASH_TYPE[:all]).
|
|
350
|
+
signature_hash_for_input(-1, nil, SIGHASH_TYPE[:all]).reverse.hth
|
|
320
351
|
end
|
|
321
352
|
alias :nhash :normalized_hash
|
|
322
353
|
|
|
@@ -85,11 +85,13 @@ module Bitcoin
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def self.from_hash(input)
|
|
88
|
-
|
|
88
|
+
previous_hash = input['previous_transaction_hash'] || input['prev_out']['hash']
|
|
89
|
+
previous_output_index = input['output_index'] || input['prev_out']['n']
|
|
90
|
+
txin = TxIn.new([ previous_hash ].pack('H*').reverse, previous_output_index)
|
|
89
91
|
if input['coinbase']
|
|
90
92
|
txin.script_sig = [ input['coinbase'] ].pack("H*")
|
|
91
93
|
else
|
|
92
|
-
txin.script_sig = Script.binary_from_string(input['scriptSig'])
|
|
94
|
+
txin.script_sig = Script.binary_from_string(input['scriptSig'] || input['script'])
|
|
93
95
|
end
|
|
94
96
|
txin.sequence = [ input['sequence'] || 0xffffffff ].pack("V")
|
|
95
97
|
txin
|
|
@@ -66,8 +66,8 @@ module Bitcoin
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def self.from_hash(output)
|
|
69
|
-
amount = output['value'].gsub('.','').to_i
|
|
70
|
-
script = Script.binary_from_string(output['scriptPubKey'])
|
|
69
|
+
amount = output['value'] ? output['value'].gsub('.','').to_i : output['amount']
|
|
70
|
+
script = Script.binary_from_string(output['scriptPubKey'] || output['script'])
|
|
71
71
|
new(amount, script)
|
|
72
72
|
end
|
|
73
73
|
|
data/lib/bitcoin/script.rb
CHANGED
|
@@ -152,24 +152,25 @@ class Bitcoin::Script
|
|
|
152
152
|
|
|
153
153
|
SIGHASH_TYPE = { all: 1, none: 2, single: 3, anyonecanpay: 128 }
|
|
154
154
|
|
|
155
|
-
attr_reader :raw, :chunks, :debug
|
|
155
|
+
attr_reader :raw, :chunks, :debug, :stack
|
|
156
156
|
|
|
157
157
|
# create a new script. +bytes+ is typically input_script + output_script
|
|
158
158
|
def initialize(input_script, previous_output_script=nil)
|
|
159
159
|
@raw_byte_sizes = [input_script.bytesize, previous_output_script ? previous_output_script.bytesize : 0]
|
|
160
|
+
@input_script, @previous_output_script = input_script, previous_output_script
|
|
160
161
|
|
|
161
|
-
@raw = if previous_output_script
|
|
162
|
-
input_script + [ Bitcoin::Script::OP_CODESEPARATOR ].pack("C") + previous_output_script
|
|
162
|
+
@raw = if @previous_output_script
|
|
163
|
+
@input_script + [ Bitcoin::Script::OP_CODESEPARATOR ].pack("C") + @previous_output_script
|
|
163
164
|
else
|
|
164
|
-
input_script
|
|
165
|
+
@input_script
|
|
165
166
|
end
|
|
166
167
|
|
|
167
|
-
@chunks = parse(input_script)
|
|
168
|
+
@chunks = parse(@input_script)
|
|
168
169
|
|
|
169
170
|
if previous_output_script
|
|
170
171
|
@script_codeseparator_index = @chunks.size
|
|
171
172
|
@chunks << Bitcoin::Script::OP_CODESEPARATOR
|
|
172
|
-
@chunks += parse(previous_output_script)
|
|
173
|
+
@chunks += parse(@previous_output_script)
|
|
173
174
|
end
|
|
174
175
|
|
|
175
176
|
@stack, @stack_alt, @exec_stack = [], [], []
|
|
@@ -354,8 +355,12 @@ class Bitcoin::Script
|
|
|
354
355
|
end
|
|
355
356
|
|
|
356
357
|
# script object of a string representation
|
|
357
|
-
def self.from_string(
|
|
358
|
-
|
|
358
|
+
def self.from_string(input_script, previous_output_script=nil)
|
|
359
|
+
if previous_output_script
|
|
360
|
+
new(binary_from_string(input_script), binary_from_string(previous_output_script))
|
|
361
|
+
else
|
|
362
|
+
new(binary_from_string(input_script))
|
|
363
|
+
end
|
|
359
364
|
end
|
|
360
365
|
|
|
361
366
|
class ScriptOpcodeError < StandardError; end
|
|
@@ -396,7 +401,7 @@ class Bitcoin::Script
|
|
|
396
401
|
end
|
|
397
402
|
|
|
398
403
|
# run the script. +check_callback+ is called for OP_CHECKSIG operations
|
|
399
|
-
def run(block_timestamp=Time.now.to_i, &check_callback)
|
|
404
|
+
def run(block_timestamp=Time.now.to_i, opts={}, &check_callback)
|
|
400
405
|
return false if @parse_invalid
|
|
401
406
|
|
|
402
407
|
#p [to_string, block_timestamp, is_p2sh?]
|
|
@@ -404,7 +409,7 @@ class Bitcoin::Script
|
|
|
404
409
|
@last_codeseparator_index = 0
|
|
405
410
|
|
|
406
411
|
if block_timestamp >= 1333238400 # Pay to Script Hash (BIP 0016)
|
|
407
|
-
return pay_to_script_hash(check_callback) if is_p2sh?
|
|
412
|
+
return pay_to_script_hash(block_timestamp, opts, check_callback) if is_p2sh?
|
|
408
413
|
end
|
|
409
414
|
|
|
410
415
|
@debug = []
|
|
@@ -430,7 +435,17 @@ class Bitcoin::Script
|
|
|
430
435
|
when *OPCODES_METHOD.keys
|
|
431
436
|
m = method( n=OPCODES_METHOD[chunk] )
|
|
432
437
|
@debug << n.to_s.upcase
|
|
433
|
-
|
|
438
|
+
# invoke opcode method
|
|
439
|
+
case m.arity
|
|
440
|
+
when 0
|
|
441
|
+
m.call
|
|
442
|
+
when 1
|
|
443
|
+
m.call(check_callback)
|
|
444
|
+
when -2 # One fixed parameter, one optional
|
|
445
|
+
m.call(check_callback, opts)
|
|
446
|
+
else
|
|
447
|
+
puts "Bitcoin::Script: opcode #{name} method parameters invalid"
|
|
448
|
+
end
|
|
434
449
|
when *OP_2_16
|
|
435
450
|
@stack << OP_2_16.index(chunk) + 2
|
|
436
451
|
@debug << "OP_#{chunk-80}"
|
|
@@ -473,17 +488,19 @@ class Bitcoin::Script
|
|
|
473
488
|
# pay_to_script_hash: https://en.bitcoin.it/wiki/BIP_0016
|
|
474
489
|
#
|
|
475
490
|
# <sig> {<pub> OP_CHECKSIG} | OP_HASH160 <script_hash> OP_EQUAL
|
|
476
|
-
def pay_to_script_hash(check_callback)
|
|
491
|
+
def pay_to_script_hash(block_timestamp, opts, check_callback)
|
|
477
492
|
return false if @chunks.size < 4
|
|
478
493
|
*rest, script, _, script_hash, _ = @chunks
|
|
479
494
|
script = rest.pop if script == OP_CODESEPARATOR
|
|
480
495
|
script, script_hash = cast_to_string(script), cast_to_string(script_hash)
|
|
481
496
|
|
|
482
497
|
return false unless Bitcoin.hash160(script.unpack("H*")[0]) == script_hash.unpack("H*")[0]
|
|
498
|
+
return true if check_callback == :check
|
|
483
499
|
|
|
484
500
|
script = self.class.new(to_binary(rest) + script).inner_p2sh!(script)
|
|
485
|
-
result = script.run(&check_callback)
|
|
501
|
+
result = script.run(block_timestamp, opts, &check_callback)
|
|
486
502
|
@debug = script.debug
|
|
503
|
+
@stack = script.stack # Set the execution stack to match the redeem script, so checks on stack contents at end of script execution validate correctly
|
|
487
504
|
result
|
|
488
505
|
end
|
|
489
506
|
|
|
@@ -501,11 +518,23 @@ class Bitcoin::Script
|
|
|
501
518
|
script
|
|
502
519
|
end
|
|
503
520
|
|
|
521
|
+
# is this a :script_hash (pay-to-script-hash/p2sh) script?
|
|
504
522
|
def is_pay_to_script_hash?
|
|
505
523
|
return false if @inner_p2sh
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
524
|
+
if @previous_output_script
|
|
525
|
+
chunks = Bitcoin::Script.new(@previous_output_script).chunks
|
|
526
|
+
chunks.size == 3 &&
|
|
527
|
+
chunks[-3] == OP_HASH160 &&
|
|
528
|
+
chunks[-2].is_a?(String) && chunks[-2].bytesize == 20 &&
|
|
529
|
+
chunks[-1] == OP_EQUAL
|
|
530
|
+
else
|
|
531
|
+
@chunks.size >= 3 &&
|
|
532
|
+
@chunks[-3] == OP_HASH160 &&
|
|
533
|
+
@chunks[-2].is_a?(String) && @chunks[-2].bytesize == 20 &&
|
|
534
|
+
@chunks[-1] == OP_EQUAL &&
|
|
535
|
+
# make sure the script_sig matches the p2sh hash from the pk_script (if there is one)
|
|
536
|
+
(@chunks.size > 3 ? pay_to_script_hash(nil, nil, :check) : true)
|
|
537
|
+
end
|
|
509
538
|
end
|
|
510
539
|
alias :is_p2sh? :is_pay_to_script_hash?
|
|
511
540
|
|
|
@@ -540,6 +569,54 @@ class Bitcoin::Script
|
|
|
540
569
|
@chunks[0] == OP_RETURN && @chunks.size <= 2
|
|
541
570
|
end
|
|
542
571
|
|
|
572
|
+
# Verify the script is only pushing data onto the stack
|
|
573
|
+
def is_push_only?(script_data=nil)
|
|
574
|
+
check_pushes(push_only=true, canonical_only=false, (script_data||@input_script))
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# Make sure opcodes used to push data match their intended length ranges
|
|
578
|
+
def pushes_are_canonical?(script_data=nil)
|
|
579
|
+
check_pushes(push_only=false, canonical_only=true, (script_data||@raw))
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def check_pushes(push_only=true, canonical_only=false, buf)
|
|
583
|
+
program = buf.unpack("C*")
|
|
584
|
+
until program.empty?
|
|
585
|
+
opcode = program.shift
|
|
586
|
+
if opcode > OP_16
|
|
587
|
+
return false if push_only
|
|
588
|
+
next
|
|
589
|
+
end
|
|
590
|
+
if opcode < OP_PUSHDATA1 && opcode > OP_0
|
|
591
|
+
# Could have used an OP_n code, rather than a 1-byte push.
|
|
592
|
+
return false if canonical_only && opcode == 1 && program[0] <= 16
|
|
593
|
+
program.shift(opcode)
|
|
594
|
+
end
|
|
595
|
+
if opcode == OP_PUSHDATA1
|
|
596
|
+
len = program.shift(1)[0]
|
|
597
|
+
# Could have used a normal n-byte push, rather than OP_PUSHDATA1.
|
|
598
|
+
return false if canonical_only && len < OP_PUSHDATA1
|
|
599
|
+
program.shift(len)
|
|
600
|
+
end
|
|
601
|
+
if opcode == OP_PUSHDATA2
|
|
602
|
+
len = program.shift(2).pack("C*").unpack("v")[0]
|
|
603
|
+
# Could have used an OP_PUSHDATA1.
|
|
604
|
+
return false if canonical_only && len <= 0xff
|
|
605
|
+
program.shift(len)
|
|
606
|
+
end
|
|
607
|
+
if opcode == OP_PUSHDATA4
|
|
608
|
+
len = program.shift(4).pack("C*").unpack("V")[0]
|
|
609
|
+
# Could have used an OP_PUSHDATA2.
|
|
610
|
+
return false if canonical_only && len <= 0xffff
|
|
611
|
+
program.shift(len)
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
true
|
|
615
|
+
rescue => ex
|
|
616
|
+
# catch parsing errors
|
|
617
|
+
false
|
|
618
|
+
end
|
|
619
|
+
|
|
543
620
|
# get type of this tx
|
|
544
621
|
def type
|
|
545
622
|
if is_hash160?; :hash160
|
|
@@ -671,9 +748,8 @@ class Bitcoin::Script
|
|
|
671
748
|
# generate input script sig spending a pubkey output with given +signature+ and +pubkey+.
|
|
672
749
|
# returns a raw binary script sig of the form:
|
|
673
750
|
# <signature> [<pubkey>]
|
|
674
|
-
def self.to_pubkey_script_sig(signature, pubkey)
|
|
675
|
-
|
|
676
|
-
buf = pack_pushdata(signature + hash_type)
|
|
751
|
+
def self.to_pubkey_script_sig(signature, pubkey, hash_type = SIGHASH_TYPE[:all])
|
|
752
|
+
buf = pack_pushdata(signature + [hash_type].pack("C"))
|
|
677
753
|
return buf unless pubkey
|
|
678
754
|
|
|
679
755
|
expected_size = case pubkey[0]
|
|
@@ -704,8 +780,9 @@ class Bitcoin::Script
|
|
|
704
780
|
# returns a raw binary script sig of the form:
|
|
705
781
|
# OP_0 <sig> [<sig> ...]
|
|
706
782
|
def self.to_multisig_script_sig(*sigs)
|
|
783
|
+
hash_type = sigs.last.is_a?(Numeric) ? sigs.pop : SIGHASH_TYPE[:all]
|
|
707
784
|
partial_script = [OP_0].pack("C*")
|
|
708
|
-
sigs.reverse_each{ |sig| partial_script = add_sig_to_multisig_script_sig(sig, partial_script) }
|
|
785
|
+
sigs.reverse_each{ |sig| partial_script = add_sig_to_multisig_script_sig(sig, partial_script, hash_type) }
|
|
709
786
|
partial_script
|
|
710
787
|
end
|
|
711
788
|
|
|
@@ -713,8 +790,8 @@ class Bitcoin::Script
|
|
|
713
790
|
# another signature to it after the OP_0. Used to sign a tx by
|
|
714
791
|
# multiple parties. Signatures must be in the same order as the
|
|
715
792
|
# pubkeys in the output script being redeemed.
|
|
716
|
-
def self.add_sig_to_multisig_script_sig(sig, script_sig)
|
|
717
|
-
signature = sig + [
|
|
793
|
+
def self.add_sig_to_multisig_script_sig(sig, script_sig, hash_type = SIGHASH_TYPE[:all])
|
|
794
|
+
signature = sig + [hash_type].pack("C*")
|
|
718
795
|
offset = script_sig.empty? ? 0 : 1
|
|
719
796
|
script_sig.insert(offset, pack_pushdata(signature))
|
|
720
797
|
end
|
|
@@ -726,6 +803,25 @@ class Bitcoin::Script
|
|
|
726
803
|
to_multisig_script_sig(*sigs.flatten) + pack_pushdata(redeem_script)
|
|
727
804
|
end
|
|
728
805
|
|
|
806
|
+
# Sort signatures in the given +script_sig+ according to the order of pubkeys in
|
|
807
|
+
# the redeem script. Also needs the +sig_hash+ to match signatures to pubkeys.
|
|
808
|
+
def self.sort_p2sh_multisig_signatures script_sig, sig_hash
|
|
809
|
+
script = new(script_sig)
|
|
810
|
+
redeem_script = new(script.chunks[-1])
|
|
811
|
+
pubkeys = redeem_script.get_multisig_pubkeys
|
|
812
|
+
|
|
813
|
+
# find the pubkey for each signature by trying to verify it
|
|
814
|
+
sigs = Hash[script.chunks[1...-1].map.with_index do |sig, idx|
|
|
815
|
+
pubkey = pubkeys.map {|key|
|
|
816
|
+
Bitcoin::Key.new(nil, key.hth).verify(sig_hash, sig) ? key : nil }.compact.first
|
|
817
|
+
raise "Key for signature ##{idx} not found in redeem script!" unless pubkey
|
|
818
|
+
[pubkey, sig]
|
|
819
|
+
end]
|
|
820
|
+
|
|
821
|
+
[OP_0].pack("C*") + pubkeys.map {|k| sigs[k] ? pack_pushdata(sigs[k]) : nil }.join +
|
|
822
|
+
pack_pushdata(redeem_script.raw)
|
|
823
|
+
end
|
|
824
|
+
|
|
729
825
|
def get_signatures_required
|
|
730
826
|
return false unless is_multisig?
|
|
731
827
|
@chunks[0] - 80
|
|
@@ -1240,14 +1336,14 @@ class Bitcoin::Script
|
|
|
1240
1336
|
# do a CHECKSIG operation on the current stack,
|
|
1241
1337
|
# asking +check_callback+ to do the actual signature verification.
|
|
1242
1338
|
# This is used by Protocol::Tx#verify_input_signature
|
|
1243
|
-
def op_checksig(check_callback)
|
|
1339
|
+
def op_checksig(check_callback, opts={})
|
|
1244
1340
|
return invalid if @stack.size < 2
|
|
1245
1341
|
pubkey = cast_to_string(@stack.pop)
|
|
1246
|
-
|
|
1342
|
+
return (@stack << 0) unless Bitcoin::Script.check_pubkey_encoding?(pubkey, opts)
|
|
1247
1343
|
drop_sigs = [ cast_to_string(@stack[-1]) ]
|
|
1248
1344
|
|
|
1249
1345
|
signature = cast_to_string(@stack.pop)
|
|
1250
|
-
|
|
1346
|
+
return invalid unless Bitcoin::Script.check_signature_encoding?(signature, opts)
|
|
1251
1347
|
return (@stack << 0) if signature == ""
|
|
1252
1348
|
|
|
1253
1349
|
sig, hash_type = parse_sig(signature)
|
|
@@ -1271,8 +1367,8 @@ class Bitcoin::Script
|
|
|
1271
1367
|
end
|
|
1272
1368
|
|
|
1273
1369
|
# Same as OP_CHECKSIG, but OP_VERIFY is executed afterward.
|
|
1274
|
-
def op_checksigverify(check_callback)
|
|
1275
|
-
op_checksig(check_callback)
|
|
1370
|
+
def op_checksigverify(check_callback, opts={})
|
|
1371
|
+
op_checksig(check_callback, opts)
|
|
1276
1372
|
op_verify
|
|
1277
1373
|
end
|
|
1278
1374
|
|
|
@@ -1289,7 +1385,7 @@ class Bitcoin::Script
|
|
|
1289
1385
|
#
|
|
1290
1386
|
# TODO: validate signature order
|
|
1291
1387
|
# TODO: take global opcode count
|
|
1292
|
-
def op_checkmultisig(check_callback)
|
|
1388
|
+
def op_checkmultisig(check_callback, opts={})
|
|
1293
1389
|
return invalid if @stack.size < 1
|
|
1294
1390
|
n_pubkeys = pop_int
|
|
1295
1391
|
return invalid unless (0..20).include?(n_pubkeys)
|
|
@@ -1312,6 +1408,8 @@ class Bitcoin::Script
|
|
|
1312
1408
|
success = true
|
|
1313
1409
|
while success && n_sigs > 0
|
|
1314
1410
|
sig, pub = sigs.pop, pubkeys.pop
|
|
1411
|
+
return (@stack << 0) unless Bitcoin::Script.check_pubkey_encoding?(pub, opts)
|
|
1412
|
+
return invalid unless Bitcoin::Script.check_signature_encoding?(sig, opts)
|
|
1315
1413
|
unless sig && sig.size > 0
|
|
1316
1414
|
success = false
|
|
1317
1415
|
break
|
|
@@ -1330,8 +1428,8 @@ class Bitcoin::Script
|
|
|
1330
1428
|
end
|
|
1331
1429
|
|
|
1332
1430
|
# Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward.
|
|
1333
|
-
def op_checkmultisigverify(check_callback)
|
|
1334
|
-
op_checkmultisig(check_callback)
|
|
1431
|
+
def op_checkmultisigverify(check_callback, opts={})
|
|
1432
|
+
op_checkmultisig(check_callback, opts)
|
|
1335
1433
|
op_verify
|
|
1336
1434
|
end
|
|
1337
1435
|
|
|
@@ -1346,7 +1444,12 @@ class Bitcoin::Script
|
|
|
1346
1444
|
OPCODES_METHOD[0] = :op_0
|
|
1347
1445
|
OPCODES_METHOD[81] = :op_1
|
|
1348
1446
|
|
|
1349
|
-
def self.
|
|
1447
|
+
def self.check_pubkey_encoding?(pubkey, opts={})
|
|
1448
|
+
return false if opts[:verify_strictenc] && !is_compressed_or_uncompressed_pub_key?(pubkey)
|
|
1449
|
+
true
|
|
1450
|
+
end
|
|
1451
|
+
|
|
1452
|
+
def self.is_compressed_or_uncompressed_pub_key?(pubkey)
|
|
1350
1453
|
return false if pubkey.bytesize < 33 # "Non-canonical public key: too short"
|
|
1351
1454
|
case pubkey[0]
|
|
1352
1455
|
when "\x04"
|
|
@@ -1359,21 +1462,93 @@ class Bitcoin::Script
|
|
|
1359
1462
|
true
|
|
1360
1463
|
end
|
|
1361
1464
|
|
|
1465
|
+
# Loosely matches CheckSignatureEncoding()
|
|
1466
|
+
def self.check_signature_encoding?(sig, opts={})
|
|
1467
|
+
return true if sig.bytesize == 0
|
|
1468
|
+
return false if (opts[:verify_dersig] || opts[:verify_low_s] || opts[:verify_strictenc]) and !is_der_signature?(sig)
|
|
1469
|
+
return false if opts[:verify_low_s] && !is_low_der_signature?(sig)
|
|
1470
|
+
return false if opts[:verify_strictenc] && !is_defined_hashtype_signature?(sig)
|
|
1471
|
+
true
|
|
1472
|
+
end
|
|
1362
1473
|
|
|
1363
|
-
|
|
1364
|
-
def self.
|
|
1474
|
+
# Loosely correlates with IsDERSignature() from interpreter.cpp
|
|
1475
|
+
def self.is_der_signature?(sig)
|
|
1365
1476
|
return false if sig.bytesize < 9 # Non-canonical signature: too short
|
|
1366
1477
|
return false if sig.bytesize > 73 # Non-canonical signature: too long
|
|
1367
1478
|
|
|
1368
1479
|
s = sig.unpack("C*")
|
|
1369
1480
|
|
|
1370
|
-
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
|
|
1371
|
-
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single] # Non-canonical signature: unknown hashtype byte
|
|
1372
|
-
|
|
1373
1481
|
return false if s[0] != 0x30 # Non-canonical signature: wrong type
|
|
1374
1482
|
return false if s[1] != s.size-3 # Non-canonical signature: wrong length marker
|
|
1375
1483
|
|
|
1376
|
-
|
|
1484
|
+
length_r = s[3]
|
|
1485
|
+
return false if (5 + length_r) >= s.size # Non-canonical signature: S length misplaced
|
|
1486
|
+
length_s = s[5+length_r]
|
|
1487
|
+
return false if (length_r + length_s + 7) != s.size # Non-canonical signature: R+S length mismatch
|
|
1488
|
+
|
|
1489
|
+
return false if s[2] != 0x02 # Non-canonical signature: R value type mismatch
|
|
1490
|
+
|
|
1491
|
+
return false if length_r == 0 # Non-canonical signature: R length is zero
|
|
1492
|
+
|
|
1493
|
+
r_val = s.slice(4, length_r)
|
|
1494
|
+
return false if r_val[0] & 0x80 != 0 # Non-canonical signature: R value negative
|
|
1495
|
+
|
|
1496
|
+
return false if length_r > 1 && (r_val[0] == 0x00) && !(r_val[1] & 0x80 != 0) # Non-canonical signature: R value excessively padded
|
|
1497
|
+
|
|
1498
|
+
s_val = s.slice(6 + length_r, length_s)
|
|
1499
|
+
return false if s[6 + length_r - 2] != 0x02 # Non-canonical signature: S value type mismatch
|
|
1500
|
+
|
|
1501
|
+
return false if length_s == 0 # Non-canonical signature: S length is zero
|
|
1502
|
+
return false if (s_val[0] & 0x80) != 0 # Non-canonical signature: S value negative
|
|
1503
|
+
|
|
1504
|
+
return false if length_s > 1 && (s_val[0] == 0x00) && !(s_val[1] & 0x80) # Non-canonical signature: S value excessively padded
|
|
1505
|
+
|
|
1506
|
+
true
|
|
1507
|
+
end
|
|
1508
|
+
|
|
1509
|
+
# Compares two arrays of bytes
|
|
1510
|
+
def self.compare_big_endian(c1, c2)
|
|
1511
|
+
c1, c2 = c1.dup, c2.dup # Clone the arrays
|
|
1512
|
+
|
|
1513
|
+
while c1.size > c2.size
|
|
1514
|
+
return 1 if c1.shift > 0
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
while c2.size > c1.size
|
|
1518
|
+
return -1 if c2.shift > 0
|
|
1519
|
+
end
|
|
1520
|
+
|
|
1521
|
+
c1.size.times{|idx| return c1[idx] - c2[idx] if c1[idx] != c2[idx] }
|
|
1522
|
+
0
|
|
1523
|
+
end
|
|
1524
|
+
|
|
1525
|
+
# Loosely correlates with IsLowDERSignature() from interpreter.cpp
|
|
1526
|
+
def self.is_low_der_signature?(sig)
|
|
1527
|
+
s = sig.unpack("C*")
|
|
1528
|
+
|
|
1529
|
+
length_r = s[3]
|
|
1530
|
+
length_s = s[5+length_r]
|
|
1531
|
+
s_val = s.slice(6 + length_r, length_s)
|
|
1532
|
+
|
|
1533
|
+
# If the S value is above the order of the curve divided by two, its
|
|
1534
|
+
# complement modulo the order could have been used instead, which is
|
|
1535
|
+
# one byte shorter when encoded correctly.
|
|
1536
|
+
max_mod_half_order = [
|
|
1537
|
+
0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
|
1538
|
+
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
|
1539
|
+
0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,
|
|
1540
|
+
0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0]
|
|
1541
|
+
|
|
1542
|
+
compare_big_endian(s_val, [0]) > 0 &&
|
|
1543
|
+
compare_big_endian(s_val, max_mod_half_order) <= 0
|
|
1544
|
+
end
|
|
1545
|
+
|
|
1546
|
+
def self.is_defined_hashtype_signature?(sig)
|
|
1547
|
+
return false if sig.empty?
|
|
1548
|
+
|
|
1549
|
+
s = sig.unpack("C*")
|
|
1550
|
+
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
|
|
1551
|
+
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single] # Non-canonical signature: unknown hashtype byte
|
|
1377
1552
|
|
|
1378
1553
|
true
|
|
1379
1554
|
end
|