interpreter.rs 49 KiB
Newer Older
use std::cmp;
Marek Kotewicz's avatar
Marek Kotewicz committed
use keys::{Public, Signature};
Marek Kotewicz's avatar
Marek Kotewicz committed
use hash::{H256, h256_from_u8};
use transaction::{Transaction, 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 script::{script, Script, Num, VerificationFlags, Opcode, Error, read_usize};
Marek Kotewicz's avatar
Marek Kotewicz committed

#[derive(Debug, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum SighashBase {
Marek Kotewicz's avatar
Marek Kotewicz committed
	All = 1,
	None = 2,
	Single = 3,
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Sighash {
	base: SighashBase,
	anyone_can_pay: bool,
}

impl From<Sighash> for u8 {
	fn from(s: Sighash) -> Self {
		let base = s.base as u8;
		match s.anyone_can_pay {
			true => base | 0x80,
			false => base,
		}
	}
}

impl Sighash {
	fn from_u8(u: u8) -> Option<Self> {
		let (base, anyone_can_pay) = match u {
			1 => (SighashBase::All, false),
			2 => (SighashBase::None, false),
			3 => (SighashBase::Single, false),
			0x81 => (SighashBase::All, true),
			0x82 => (SighashBase::None, true),
			0x83 => (SighashBase::Single, true),
			_ => return None,
		};

		let sighash = Sighash {
			base: base,
			anyone_can_pay: anyone_can_pay
		};

		Some(sighash)
	}
Marek Kotewicz's avatar
Marek Kotewicz committed

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SignatureVersion {
Marek Kotewicz's avatar
Marek Kotewicz committed
	Base,
	WitnessV0,
Marek Kotewicz's avatar
Marek Kotewicz committed
}

pub trait SignatureChecker {
Marek Kotewicz's avatar
Marek Kotewicz committed
	fn check_signature(
		&self,
		script_signature: &[u8],
Marek Kotewicz's avatar
Marek Kotewicz committed
		public: &[u8],
Marek Kotewicz's avatar
Marek Kotewicz committed
		script: &Script,
		version: SignatureVersion
	) -> bool;
Marek Kotewicz's avatar
Marek Kotewicz committed
	fn check_lock_time(&self, lock_time: Num) -> bool;

	fn check_sequence(&self, sequence: Num) -> bool;
}

pub struct NoopSignatureChecker;

impl SignatureChecker for NoopSignatureChecker {
Marek Kotewicz's avatar
Marek Kotewicz committed
	fn check_signature(&self, _: &[u8], _: &[u8], _: &Script, _: SignatureVersion) -> bool {
Marek Kotewicz's avatar
Marek Kotewicz committed
		false
	}

	fn check_lock_time(&self, _: Num) -> bool {
		false
	}

	fn check_sequence(&self, _: Num) -> bool {
		false
	}
}

pub struct TransactionSignatureChecker {
	transaction: Transaction,
	i: u32,
	amount: i64,
}

impl TransactionSignatureChecker {
Marek Kotewicz's avatar
Marek Kotewicz committed
	fn verify_signature(&self, _signature: &[u8], _public: &[u8], _hash: &H256) -> bool {
Marek Kotewicz's avatar
Marek Kotewicz committed
		unimplemented!();
	}
}

impl SignatureChecker for TransactionSignatureChecker {
	fn check_signature(
		&self,
Marek Kotewicz's avatar
Marek Kotewicz committed
		script_signature: &[u8],
		public: &[u8],
Marek Kotewicz's avatar
Marek Kotewicz committed
		_script: &Script,
		_version: SignatureVersion
	) -> bool {
Marek Kotewicz's avatar
Marek Kotewicz committed
		let public = match Public::from_slice(public) {
			Ok(public) => public,
			_ => return false,
		};

		if script_signature.is_empty() {
			return false;
		}

		let _hash_type = script_signature.last().unwrap();
Marek Kotewicz's avatar
Marek Kotewicz committed
		unimplemented!();
	}

	fn check_lock_time(&self, _lock_time: Num) -> bool {
		unimplemented!();
	}

	fn check_sequence(&self, _sequence: Num) -> bool {
		unimplemented!();
	}
Marek Kotewicz's avatar
Marek Kotewicz committed
fn signature_hash(
	_script_code: &Script,
Marek Kotewicz's avatar
Marek Kotewicz committed
	tx: &Transaction,
	i: usize,
	hash_type: i32,
	_amount: u32,
	_version: SignatureVersion
Marek Kotewicz's avatar
Marek Kotewicz committed
) -> H256 {
	if i >= tx.transaction_inputs().len() {
		return h256_from_u8(1);
	}

	if (hash_type & 0x1f) == SighashBase::Single as i32 {
Marek Kotewicz's avatar
Marek Kotewicz committed
		if i >= tx.transaction_outputs().len() {
			return h256_from_u8(1);
		}
	}

	unimplemented!();
}

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;

Loading full blame...