lib/bitcoin/script.rb in bitcoin-ruby-0.0.2 vs lib/bitcoin/script.rb in bitcoin-ruby-0.0.3
- old
+ new
@@ -990,13 +990,19 @@
# asking +check_callback+ to do the actual signature verification.
# This is used by Protocol::Tx#verify_input_signature
def op_checksig(check_callback)
return invalid if @stack.size < 2
pubkey = @stack.pop
+ #return (@stack << 0) unless Bitcoin::Script.is_canonical_pubkey?(pubkey) # only for isStandard
drop_sigs = [ @stack[-1] ]
- sig, hash_type = parse_sig(@stack.pop)
+ signature = cast_to_string(@stack.pop)
+ #return (@stack << 0) unless Bitcoin::Script.is_canonical_signature?(signature) # only for isStandard
+ return (@stack << 0) if signature == ""
+
+ sig, hash_type = parse_sig(signature)
+
if inner_p2sh?
script_code = @inner_script_code || to_binary_without_signatures(drop_sigs)
drop_sigs = nil
else
script_code, drop_sigs = nil, nil
@@ -1036,24 +1042,26 @@
pubkeys = pop_string(n_pubkeys)
n_sigs = pop_int
return invalid unless (0..n_pubkeys).include?(n_sigs)
return invalid unless @stack.last(n_sigs).all?{|e| e.is_a?(String) && e != '' }
- sigs = (drop_sigs = pop_string(n_sigs)).map{|s| parse_sig(s) }
+ sigs = drop_sigs = pop_string(n_sigs)
- @stack.pop if @stack[-1] == '' # remove OP_NOP from stack
+ @stack.pop if @stack[-1] && cast_to_bignum(@stack[-1]) == 0 # remove OP_0 from stack
if inner_p2sh?
script_code = @inner_script_code || to_binary_without_signatures(drop_sigs)
drop_sigs = nil
else
script_code, drop_sigs = nil, nil
end
valid_sigs = 0
- sigs.each{|sig, hash_type| pubkeys.each{|pubkey|
- valid_sigs += 1 if check_callback.call(pubkey, sig, hash_type, drop_sigs, script_code)
+ sigs.each{|sig| pubkeys.each{|pubkey|
+ next if sig == ""
+ signature, hash_type = parse_sig(sig)
+ valid_sigs += 1 if check_callback.call(pubkey, signature, hash_type, drop_sigs, script_code)
}}
@stack << ((valid_sigs >= n_sigs) ? 1 : (invalid; 0))
end
@@ -1078,9 +1086,30 @@
else
return false # "Non-canonical public key: compressed nor uncompressed"
end
true
end
+
+
+ SIGHASH_TYPE = { all: 1, none: 2, single: 3, anyonecanpay: 128 }
+
+ def self.is_canonical_signature?(sig)
+ return false if sig.bytesize < 9 # Non-canonical signature: too short
+ return false if sig.bytesize > 73 # Non-canonical signature: too long
+
+ s = sig.unpack("C*")
+
+ hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
+ return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single] # Non-canonical signature: unknown hashtype byte
+
+ return false if s[0] != 0x30 # Non-canonical signature: wrong type
+ return false if s[1] != s.size-3 # Non-canonical signature: wrong length marker
+
+ # TODO: add/port rest from bitcoind
+
+ true
+ end
+
private
def parse_sig(sig)
hash_type = sig[-1].unpack("C")[0]