diff --git a/script/src/interpreter.rs b/script/src/interpreter.rs index b2f0f160..4f0ad979 100644 --- a/script/src/interpreter.rs +++ b/script/src/interpreter.rs @@ -149,15 +149,15 @@ fn is_low_der_signature(sig: &[u8]) -> Result<(), Error> { Ok(()) } -fn is_defined_hashtype_signature(sig: &[u8]) -> bool { +fn is_defined_hashtype_signature(version: SignatureVersion, sig: &[u8]) -> bool { if sig.is_empty() { return false; } - Sighash::is_defined(sig[sig.len() -1] as u32) + Sighash::is_defined(version, sig[sig.len() -1] as u32) } -fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags) -> Result<(), Error> { +fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: SignatureVersion) -> Result<(), Error> { // Empty signature. Not strictly DER encoded, but allowed to provide a // compact way to provide an invalid signature for use with CHECK(MULTI)SIG @@ -173,7 +173,7 @@ fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags) -> Result<(), try!(is_low_der_signature(sig)); } - if flags.verify_strictenc && !is_defined_hashtype_signature(sig) { + if flags.verify_strictenc && !is_defined_hashtype_signature(version, sig) { Err(Error::SignatureHashtype) } else { Ok(()) @@ -778,7 +778,7 @@ pub fn eval_script( subscript = subscript.find_and_delete(&*signature_script); } - try!(check_signature_encoding(&signature, flags)); + try!(check_signature_encoding(&signature, flags, version)); try!(check_pubkey_encoding(&pubkey, flags)); let success = check_signature(checker, signature.into(), pubkey.into(), &subscript, version); @@ -830,7 +830,7 @@ pub fn eval_script( let key = keys[k].clone(); let sig = sigs[s].clone(); - try!(check_signature_encoding(&sig, flags)); + try!(check_signature_encoding(&sig, flags, version)); try!(check_pubkey_encoding(&key, flags)); let ok = check_signature(checker, sig.into(), key.into(), &subscript, version); diff --git a/script/src/sign.rs b/script/src/sign.rs index f9bf4cc8..0e1f550a 100644 --- a/script/src/sign.rs +++ b/script/src/sign.rs @@ -55,18 +55,6 @@ impl From for u32 { } } -impl From for Sighash { - fn from(u: u32) -> Self { - Sighash::new(match u & 0x1f { - 2 => SighashBase::None, - 3 => SighashBase::Single, - 1 | _ => SighashBase::All, - }, - u & 0x80 == 0x80, - u & 0x40 == 0x40 && u & 0xFFFFFF00 == 0) - } -} - impl Sighash { pub fn new(base: SighashBase, anyone_can_pay: bool, fork_id: bool) -> Self { Sighash { @@ -76,36 +64,32 @@ impl Sighash { } } - pub fn is_defined(u: u32) -> bool { - // fork id must be zero - if u & 0x40 == 0x40 && u & 0xFFFFFF00 != 0 { - return false; - } + /// Used by SCRIPT_VERIFY_STRICTENC + pub fn is_defined(version: SignatureVersion, u: u32) -> bool { + // reset anyone_can_pay && fork_id (if applicable) bits + let u = match version { + SignatureVersion::ForkId => u & !(0x40 | 0x80), + _ => u & !(0x80), + }; - // use 0xdf istead of 0x1f to catch 0x40 | 0x80 - match u & 0xdf { - 1 | 2 | 3 | - 0x81 | 0x82 | 0x83 | - 0x41 | 0x42 | 0x43 | - 0xc1 | 0xc2 | 0xc3 => true, - x if x & 0x80 == 0x80 => true, - x if x & 0x40 == 0x40 => true, + // Only exact All | None | Single values are passing this check + match u { + 1 | 2 | 3 => true, _ => false, } } - pub fn from_u32(u: u32) -> Option { + /// Creates Sighash from any u, even if is_defined() == false + pub fn from_u32(version: SignatureVersion, u: u32) -> Self { let anyone_can_pay = (u & 0x80) == 0x80; - let fork_id = (u & 0x40) == 0x40; + let fork_id = version == SignatureVersion::ForkId && (u & 0x40) == 0x40; let base = match u & 0x1f { 2 => SighashBase::None, 3 => SighashBase::Single, - 1 => SighashBase::All, - _ if anyone_can_pay || fork_id => SighashBase::All, - _ => return None, + 1 | _ => SighashBase::All, }; - Some(Sighash::new(base, anyone_can_pay, fork_id)) + Sighash::new(base, anyone_can_pay, fork_id) } } @@ -145,7 +129,7 @@ impl From for TransactionInputSigner { impl TransactionInputSigner { pub fn signature_hash(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sigversion: SignatureVersion, sighashtype: u32) -> H256 { - let sighash = Sighash::from(sighashtype); + let sighash = Sighash::from_u32(sigversion, sighashtype); if input_index >= self.inputs.len() { return 1u8.into(); } @@ -154,9 +138,9 @@ impl TransactionInputSigner { return 1u8.into(); } - match sighash.fork_id { - true if sigversion == SignatureVersion::ForkId => self.signature_hash_fork_id(input_index, input_amount, script_pubkey, sighashtype, sighash), - false if sigversion == SignatureVersion::Base => self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash), + match sigversion { + SignatureVersion::Base => self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash), + SignatureVersion::ForkId if sighash.fork_id => self.signature_hash_fork_id(input_index, input_amount, script_pubkey, sighashtype, sighash), _ => 1u8.into(), } } @@ -365,7 +349,8 @@ mod tests { let script: Script = script.into(); let expected = H256::from_reversed_str(result); - let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, (hash_type as u32).into()); + let sighash = Sighash::from_u32(SignatureVersion::Base, hash_type as u32); + let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, sighash); assert_eq!(expected, hash); } @@ -877,8 +862,17 @@ mod tests { #[test] fn test_sighash_forkid_from_u32() { - assert!(!Sighash::is_defined(0b11111111111111111111111101000010)); // non-zero fork id - assert!(!Sighash::is_defined(0b00000000000000000000000101000010)); // non-zero fork id - assert!(Sighash::is_defined(0b00000000000000000000000001000010)); // zero fork id + assert!(!Sighash::is_defined(SignatureVersion::Base, 0xFFFFFF82)); + assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000182)); + assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000080)); + assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000001)); + assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000082)); + assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000003)); + + assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0xFFFFFFC2)); + assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0x000001C2)); + assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x00000081)); + assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x000000C2)); + assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x00000043)); } }