From 78bd3e54857a6ea7f59f7ea10a5a5e1b40863fd7 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 15 Aug 2017 11:26:09 +0300 Subject: [PATCH] FORKID sighash fixes --- script/src/error.rs | 4 ++++ script/src/interpreter.rs | 26 +++++++++++++++++++++----- script/src/sign.rs | 4 ++-- script/src/verify.rs | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/script/src/error.rs b/script/src/error.rs index 03be5c48..dbaab08e 100644 --- a/script/src/error.rs +++ b/script/src/error.rs @@ -40,6 +40,8 @@ pub enum Error { // BIP62 SignatureHashtype, SignatureDer, + SignatureIllegalForkId, + SignatureMustUseForkId, Minimaldata, SignaturePushOnly, SignatureHighS, @@ -88,6 +90,8 @@ impl fmt::Display for Error { // BIP62 Error::SignatureHashtype => "Invalid Signature Hashtype".fmt(f), Error::SignatureDer => "Invalid Signature".fmt(f), + Error::SignatureIllegalForkId => "Illegal use of SIGHASH_FORKID".fmt(f), + Error::SignatureMustUseForkId => "Signature must use SIGHASH_FORKID".fmt(f), Error::Minimaldata => "Check minimaldata failed".fmt(f), Error::SignaturePushOnly => "Only push opcodes are allowed in this signature".fmt(f), Error::SignatureHighS => "Invalid High S in Signature".fmt(f), diff --git a/script/src/interpreter.rs b/script/src/interpreter.rs index 279d299d..b9a34d70 100644 --- a/script/src/interpreter.rs +++ b/script/src/interpreter.rs @@ -154,7 +154,11 @@ fn is_defined_hashtype_signature(version: SignatureVersion, sig: &[u8]) -> bool return false; } - Sighash::is_defined(version, sig[sig.len() -1] as u32) + Sighash::is_defined(version, sig[sig.len() - 1] as u32) +} + +fn parse_hash_type(version: SignatureVersion, sig: &[u8]) -> Sighash { + Sighash::from_u32(version, if sig.is_empty() { 0 } else { sig[sig.len() - 1] as u32 }) } fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: SignatureVersion) -> Result<(), Error> { @@ -174,10 +178,21 @@ fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: Sign } if flags.verify_strictenc && !is_defined_hashtype_signature(version, sig) { - Err(Error::SignatureHashtype) - } else { - Ok(()) + return Err(Error::SignatureHashtype) } + + // verify_strictenc is currently enabled for BitcoinCash only + if flags.verify_strictenc { + let uses_fork_id = parse_hash_type(version, sig).fork_id; + let enabled_fork_id = version == SignatureVersion::ForkId; + if uses_fork_id && !enabled_fork_id { + return Err(Error::SignatureIllegalForkId) + } else if !uses_fork_id && enabled_fork_id { + return Err(Error::SignatureMustUseForkId); + } + } + + Ok(()) } fn check_pubkey_encoding(v: &[u8], flags: &VerificationFlags) -> Result<(), Error> { @@ -772,8 +787,9 @@ pub fn eval_script( Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => { let pubkey = try!(stack.pop()); let signature = try!(stack.pop()); + let sighash = parse_hash_type(version, &signature); let mut subscript = script.subscript(begincode); - if version == SignatureVersion::Base { + if version != SignatureVersion::ForkId || !sighash.fork_id { let signature_script = Builder::default().push_data(&*signature).into_script(); subscript = subscript.find_and_delete(&*signature_script); } diff --git a/script/src/sign.rs b/script/src/sign.rs index 0dd35a82..50680e3d 100644 --- a/script/src/sign.rs +++ b/script/src/sign.rs @@ -141,8 +141,8 @@ impl TransactionInputSigner { } 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), + SignatureVersion::Base | SignatureVersion::ForkId => self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash), _ => 1u8.into(), } } @@ -275,7 +275,7 @@ impl TransactionInputSigner { stream.append(&hash_prevouts); stream.append(&hash_sequence); stream.append(&self.inputs[input_index].previous_output); - stream.append_slice(&**script_pubkey); + stream.append_list(&**script_pubkey); stream.append(&input_amount); stream.append(&self.inputs[input_index].sequence); stream.append(&hash_outputs); diff --git a/script/src/verify.rs b/script/src/verify.rs index 0addc1b5..5e87b591 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -38,6 +38,7 @@ impl SignatureChecker for NoopSignatureChecker { } } +#[derive(Debug)] pub struct TransactionSignatureChecker { pub signer: TransactionInputSigner, pub input_index: usize,