interpreter.rs 174 KiB
Newer Older
use std::{cmp, mem};
Marek Kotewicz's avatar
Marek Kotewicz committed
use bytes::Bytes;
use keys::{Message, Signature, Public};
use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG;
Marek Kotewicz's avatar
Marek Kotewicz committed
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
Marek Kotewicz's avatar
Marek Kotewicz committed
use sign::{SignatureVersion, Sighash};
use script::MAX_SCRIPT_ELEMENT_SIZE;
Marek Kotewicz's avatar
Marek Kotewicz committed
use {
	script, Builder, Script, ScriptWitness, Num, VerificationFlags, Opcode, Error, SignatureChecker, Stack
/// Helper function.
fn check_signature(
amanusk's avatar
amanusk committed
	checker: &dyn SignatureChecker,
	script_sig: &Vec<u8>,
	public: &Vec<u8>,
	script_code: &Script,
	version: SignatureVersion
) -> bool {
	let public = match Public::from_slice(&public) {
		Ok(public) => public,
		_ => return false,
	};
	if let Some((hash_type, sig)) = script_sig.split_last() {
		checker.check_signature(&sig.into(), &public, script_code, *hash_type as u32, version)
	} else {
		return false
/// Helper function.
fn verify_signature(
amanusk's avatar
amanusk committed
	checker: &dyn SignatureChecker,
	signature: Vec<u8>,
	public: Vec<u8>,
	message: Message,
) -> bool {
	let public = match Public::from_slice(&public) {
		Ok(public) => public,
		_ => return false,
	};

	if signature.is_empty() {
		return false;
	}

	checker.verify_signature(&signature.into(), &public, &message.into())
}

Marek Kotewicz's avatar
Marek Kotewicz committed
fn is_public_key(v: &[u8]) -> bool {
	match v.len() {
		33 if v[0] == 2 || v[0] == 3 => true,
		65 if v[0] == 4 => true,
		_ => false,
	}
}

/// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
/// Where R and S are not negative (their first byte has its highest bit not set), and not
/// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
/// in which case a single 0 byte is necessary and even required).
///
/// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
///
/// This function is consensus-critical since BIP66.
fn is_valid_signature_encoding(sig: &[u8]) -> bool {
	// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
	// * total-length: 1-byte length descriptor of everything that follows,
	//   excluding the sighash byte.
	// * R-length: 1-byte length descriptor of the R value that follows.
	// * R: arbitrary-length big-endian encoded R value. It must use the shortest
	//   possible encoding for a positive integers (which means no null bytes at
	//   the start, except a single one when the next byte has its highest bit set).
	// * S-length: 1-byte length descriptor of the S value that follows.
	// * S: arbitrary-length big-endian encoded S value. The same rules apply.
	// * sighash: 1-byte value indicating what data is hashed (not part of the DER
	//   signature)

	// Minimum and maximum size constraints
	if sig.len() < 9 || sig.len() > 73 {
		return false;
	}

	// A signature is of type 0x30 (compound)
	if sig[0] != 0x30 {
		return false;
	}

	// Make sure the length covers the entire signature.
	if sig[1] as usize != sig.len() - 3 {
		return false;
	}

	// Extract the length of the R element.
	let len_r = sig[3] as usize;

	// Make sure the length of the S element is still inside the signature.
	if len_r + 5 >= sig.len() {
		return false;
	}

	// Extract the length of the S element.
	let len_s = sig[len_r + 5] as usize;

	// Verify that the length of the signature matches the sum of the length
	if len_r + len_s + 7 != sig.len() {
		return false;
	}

	// Check whether the R element is an integer.
	if sig[2] != 2 {
		return false;
	}

	// Zero-length integers are not allowed for R.
	if len_r == 0 {
		return false;
	}

	// Negative numbers are not allowed for R.
	if (sig[4] & 0x80) != 0 {
		return false;
	}

	// Null bytes at the start of R are not allowed, unless R would
	// otherwise be interpreted as a negative number.
	if len_r > 1 && sig[4] == 0 && (sig[5] & 0x80) == 0 {
Marek Kotewicz's avatar
Marek Kotewicz committed
		return false;
	}

	// Check whether the S element is an integer.
	if sig[len_r + 4] != 2 {
		return false;
	}

	// Zero-length integers are not allowed for S.
	if len_s == 0 {
		return false;
	}

	// Negative numbers are not allowed for S.
	if (sig[len_r + 6] & 0x80) != 0 {
		return false;
	}

	// Null bytes at the start of S are not allowed, unless S would otherwise be
	// interpreted as a negative number.
	if len_s > 1 && (sig[len_r + 6] == 0) && (sig[len_r + 7] & 0x80) == 0 {
Marek Kotewicz's avatar
Marek Kotewicz committed
fn is_low_der_signature(sig: &[u8]) -> Result<(), Error> {
Marek Kotewicz's avatar
Marek Kotewicz committed
	if !is_valid_signature_encoding(sig) {
		return Err(Error::SignatureDer);
	}

	let signature: Signature = sig.into();
	if !signature.check_low_s() {
		return Err(Error::SignatureHighS);
	}

Marek Kotewicz's avatar
Marek Kotewicz committed
	Ok(())
fn is_defined_hashtype_signature(version: SignatureVersion, sig: &[u8]) -> bool {
Marek Kotewicz's avatar
Marek Kotewicz committed
	if sig.is_empty() {
		return false;
	}

	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> {
Marek Kotewicz's avatar
Marek Kotewicz committed
	// Empty signature. Not strictly DER encoded, but allowed to provide a
	// compact way to provide an invalid signature for use with CHECK(MULTI)SIG

	if sig.is_empty() {
Marek Kotewicz's avatar
Marek Kotewicz committed
		return Ok(());
Marek Kotewicz's avatar
Marek Kotewicz committed
	}

	if (flags.verify_dersig || flags.verify_low_s || flags.verify_strictenc) && !is_valid_signature_encoding(sig) {
Marek Kotewicz's avatar
Marek Kotewicz committed
		return Err(Error::SignatureDer);
	}

	if flags.verify_low_s {
		is_low_der_signature(sig)?;
	if flags.verify_strictenc && !is_defined_hashtype_signature(version, sig) {
		return Err(Error::SignatureHashtype)
	}

Loading full blame...