text: use keys::{Public, Signature, Message};
  use chain::constants::{
  	SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG,
  	SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG, LOCKTIME_THRESHOLD
  };
  use {Script, SighashCache, TransactionInputSigner, Num};
  
  /// Checks transaction signature
  pub trait SignatureChecker {
  	fn verify_signature(
  		&self,
  		signature: &Signature,
  		public: &Public,
  		hash: &Message,
  	) -> bool;
  
  	fn check_signature(
  		&mut self,
  		signature: &Signature,
  		public: &Public,
  		script_code: &Script,
  		sighashtype: u32,
  	) -> bool;
  
  	fn check_lock_time(&self, lock_time: Num) -> bool;
  
  	fn check_sequence(&self, sequence: Num) -> bool;
  }
  
  pub struct NoopSignatureChecker;
  
  impl SignatureChecker for NoopSignatureChecker {
  	fn verify_signature(&self, signature: &Signature, public: &Public, hash: &Message) -> bool {
  		public.verify(hash, signature).unwrap_or(false)
  	}
  
  	fn check_signature(&mut self, _: &Signature, _: &Public, _: &Script, _: u32) -> bool {
  		false
  	}
  
  	fn check_lock_time(&self, _: Num) -> bool {
  		false
  	}
  
  	fn check_sequence(&self, _: Num) -> bool {
  		false
  	}
  }
  
  #[derive(Debug)]
  pub struct TransactionSignatureChecker {
  	pub signer: TransactionInputSigner,
  	pub input_index: usize,
  	pub input_amount: u64,
  	pub consensus_branch_id: u32,
  	pub cache: SighashCache,
  }
  
  impl SignatureChecker for TransactionSignatureChecker {
  	fn verify_signature(
  		&self,
  		signature: &Signature,
  		public: &Public,
  		hash: &Message,
  	) -> bool {
  		public.verify(hash, signature).unwrap_or(false)
  	}
  
  	fn check_signature(
  		&mut self,
  		signature: &Signature,
  		public: &Public,
  		script_code: &Script,
  		sighashtype: u32,
  	) -> bool {
  		let hash = self.signer.signature_hash(
  			&mut self.cache,
  			Some(self.input_index),
  			self.input_amount,
  			script_code,
  			sighashtype,
  			self.consensus_branch_id,
  		);
  		self.verify_signature(signature, public, &hash)
  	}
  
  	fn check_lock_time(&self, lock_time: Num) -> bool {
  		// There are two kinds of nLockTime: lock-by-blockheight
  		// and lock-by-blocktime, distinguished by whether
  		// nLockTime < LOCKTIME_THRESHOLD.
  		//
  		// We want to compare apples to apples, so fail the script
  		// unless the type of nLockTime being tested is the same as
  		// the nLockTime in the transaction.
  		let lock_time_u32: u32 = lock_time.into();
  		if !(
  			(self.signer.lock_time < LOCKTIME_THRESHOLD && lock_time_u32 < LOCKTIME_THRESHOLD) ||
  			(self.signer.lock_time >= LOCKTIME_THRESHOLD && lock_time_u32 >= LOCKTIME_THRESHOLD)
  		) {
  			return false;
  		}
  
  		// Now that we know we're comparing apples-to-apples, the
  		// comparison is a simple numeric one.
  		if i64::from(lock_time) > self.signer.lock_time as i64 {
  			return false;
  		}
  
  		// Finally the nLockTime feature can be disabled and thus
  		// CHECKLOCKTIMEVERIFY bypassed if every txin has been
  		// finalized by setting nSequence to maxint. The
  		// transaction would be allowed into the blockchain, making
  		// the opcode ineffective.
  		//
  		// Testing if this vin is not final is sufficient to
  		// prevent this condition. Alternatively we could test all
  		// inputs, but testing just this input minimizes the data
  		// required to prove correct CHECKLOCKTIMEVERIFY execution.
  		SEQUENCE_FINAL != self.signer.inputs[self.input_index].sequence
  	}
  
  	fn check_sequence(&self, sequence: Num) -> bool {
  		// Relative lock times are supported by comparing the passed
  		// in operand to the sequence number of the input.
  		let to_sequence: i64 = self.signer.inputs[self.input_index].sequence as i64;
  
  		// Fail if the transaction's version number is not set high
  		// enough to trigger BIP 68 rules.
  		if (self.signer.version as u32) < 2 {
  			return false;
  		}
  
  		// Sequence numbers with their most significant bit set are not
  		// consensus constrained. Testing that the transaction's sequence
  		// number do not have this bit set prevents using this property
  		// to get around a CHECKSEQUENCEVERIFY check.
  		if to_sequence & SEQUENCE_LOCKTIME_DISABLE_FLAG as i64 != 0 {
  			return false;
  		}
  
  		// Mask off any bits that do not have consensus-enforced meaning
  		// before doing the integer comparisons
  		let locktime_mask: u32 = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK;
  		let to_sequence_masked: i64 = to_sequence & locktime_mask as i64;
  		let sequence_masked: i64 = i64::from(sequence) & locktime_mask as i64;
  
  		// There are two kinds of nSequence: lock-by-blockheight
  		// and lock-by-blocktime, distinguished by whether
  		// nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
  
  		// We want to compare apples to apples, so fail the script
  		// unless the type of nSequenceMasked being tested is the same as
  		// the nSequenceMasked in the transaction.
  		if !(
  			(to_sequence_masked < SEQUENCE_LOCKTIME_TYPE_FLAG as i64 && sequence_masked < SEQUENCE_LOCKTIME_TYPE_FLAG as i64) ||
  			(to_sequence_masked >= SEQUENCE_LOCKTIME_TYPE_FLAG as i64 && sequence_masked >= SEQUENCE_LOCKTIME_TYPE_FLAG as i64)
  		) {
  			return false;
  		}
  
  		// Now that we know we're comparing apples-to-apples, the
  		// comparison is a simple numeric one.
  		sequence_masked <= to_sequence_masked
  	}
  }
  