Remove entire signature push operation, not just signature data, when hashing for checksig

This commit is contained in:
Andrew Poelstra 2014-08-11 21:38:46 -07:00
parent 2469820863
commit 38593dd2ab
2 changed files with 46 additions and 27 deletions

View File

@ -43,7 +43,7 @@ use blockdata::transaction::Transaction;
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{SimpleDecoder, SimpleEncoder, serialize}; use network::serialize::{SimpleDecoder, SimpleEncoder, serialize};
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
use util::misc::find_and_remove; use util::misc::script_find_and_remove;
use util::thinvec::ThinVec; use util::thinvec::ThinVec;
#[deriving(PartialEq, Show, Clone)] #[deriving(PartialEq, Show, Clone)]
@ -421,6 +421,12 @@ impl Script {
raw.push(data as u8); raw.push(data as u8);
} }
/// Returns a view into the script as a slice
pub fn as_slice(&self) -> &[u8] {
let &Script(ref raw) = self;
raw.as_slice()
}
/// Evaluate the script, modifying the stack in place /// Evaluate the script, modifying the stack in place
pub fn evaluate(&self, stack: &mut Vec<Vec<u8>>, input_context: Option<(&Transaction, uint)>) pub fn evaluate(&self, stack: &mut Vec<Vec<u8>>, input_context: Option<(&Transaction, uint)>)
-> Result<(), ScriptError> { -> Result<(), ScriptError> {
@ -634,7 +640,9 @@ impl Script {
// Compute the section of script that needs to be hashed: everything // Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signature itself. // from the last CODESEPARATOR, except the signature itself.
let mut script = Vec::from_slice(raw.slice_from(codeseparator_index)); let mut script = Vec::from_slice(raw.slice_from(codeseparator_index));
find_and_remove(&mut script, sig_slice); let mut remove = Script::new();
remove.push_slice(sig_slice);
script_find_and_remove(&mut script, remove.as_slice());
// This is as far as we can go without a transaction, so fail here // This is as far as we can go without a transaction, so fail here
if input_context.is_none() { return Err(NoTransaction); } if input_context.is_none() { return Err(NoTransaction); }
@ -681,7 +689,9 @@ impl Script {
// from the last CODESEPARATOR, except the signatures themselves. // from the last CODESEPARATOR, except the signatures themselves.
let mut script = Vec::from_slice(raw.slice_from(codeseparator_index)); let mut script = Vec::from_slice(raw.slice_from(codeseparator_index));
for sig in sigs.iter() { for sig in sigs.iter() {
find_and_remove(&mut script, sig.as_slice()); let mut remove = Script::new();
remove.push_slice(sig.as_slice());
script_find_and_remove(&mut script, remove.as_slice());
} }
// This is as far as we can go without a transaction, so fail here // This is as far as we can go without a transaction, so fail here
@ -695,7 +705,6 @@ impl Script {
let mut key = key_iter.next(); let mut key = key_iter.next();
let mut sig = sig_iter.next(); let mut sig = sig_iter.next();
loop { loop {
//println!("key({}) {} sig({}) {}", key.map(|k| k.len()), key, sig.map(|s| s.len()), sig);
match (key, sig) { match (key, sig) {
// Try to validate the signature with the given key // Try to validate the signature with the given key
(Some(k), Some(s)) => { (Some(k), Some(s)) => {
@ -1007,6 +1016,7 @@ mod test {
#[test] #[test]
fn script_eval_testnet_failure_7() { fn script_eval_testnet_failure_7() {
// script_find_and_delete needs to drop the entire push operation, not just the signature data
// txid 2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1 // txid 2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1
let tx_hex = "01000000022f196cf1e5bd426a04f07b882c893b5b5edebad67da6eb50f066c372ed736d5f000000006a47304402201f81ac31b52cb4b1ceb83f97d18476f7339b74f4eecd1a32c251d4c3cccfffa402203c9143c18810ce072969e4132fdab91408816c96b423b2be38eec8a3582ade36012102aa5a2b334bd8f135f11bc5c477bf6307ff98ed52d3ed10f857d5c89adf5b02beffffffffff8755f073f1170c0d519457ffc4acaa7cb2988148163b5dc457fae0fe42aa19000000009200483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a530347304402206da827fb26e569eb740641f9c1a7121ee59141703cbe0f903a22cc7d9a7ec7ac02204729f989b5348b3669ab020b8c4af01acc4deaba7c0d9f8fa9e06b2106cbbfeb01ffffffff010000000000000000016a00000000".from_hex().unwrap(); let tx_hex = "01000000022f196cf1e5bd426a04f07b882c893b5b5edebad67da6eb50f066c372ed736d5f000000006a47304402201f81ac31b52cb4b1ceb83f97d18476f7339b74f4eecd1a32c251d4c3cccfffa402203c9143c18810ce072969e4132fdab91408816c96b423b2be38eec8a3582ade36012102aa5a2b334bd8f135f11bc5c477bf6307ff98ed52d3ed10f857d5c89adf5b02beffffffffff8755f073f1170c0d519457ffc4acaa7cb2988148163b5dc457fae0fe42aa19000000009200483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a530347304402206da827fb26e569eb740641f9c1a7121ee59141703cbe0f903a22cc7d9a7ec7ac02204729f989b5348b3669ab020b8c4af01acc4deaba7c0d9f8fa9e06b2106cbbfeb01ffffffff010000000000000000016a00000000".from_hex().unwrap();

View File

@ -18,6 +18,8 @@
use std::io::{IoError, IoResult, InvalidInput}; use std::io::{IoError, IoResult, InvalidInput};
use blockdata::opcodes;
use blockdata::opcodes::all::Opcode;
use util::iter::Pairable; use util::iter::Pairable;
/// Convert a hexadecimal-encoded string to its corresponding bytes /// Convert a hexadecimal-encoded string to its corresponding bytes
@ -75,7 +77,8 @@ pub fn consume_err<T>(s: &str, res: IoResult<T>) {
/// Search for `needle` in the vector `haystack` and remove every /// Search for `needle` in the vector `haystack` and remove every
/// instance of it, returning the number of instances removed. /// instance of it, returning the number of instances removed.
pub fn find_and_remove<T:Eq+::std::fmt::Show>(haystack: &mut Vec<T>, needle: &[T]) -> uint { /// Loops through the vector opcode by opcode, skipping pushed data.
pub fn script_find_and_remove(haystack: &mut Vec<u8>, needle: &[u8]) -> uint {
if needle.len() > haystack.len() { return 0; } if needle.len() > haystack.len() { return 0; }
if needle.len() == 0 { return 0; } if needle.len() == 0 { return 0; }
@ -95,7 +98,13 @@ pub fn find_and_remove<T:Eq+::std::fmt::Show>(haystack: &mut Vec<T>, needle: &[T
top -= needle.len(); top -= needle.len();
if overflow { break; } if overflow { break; }
} else { } else {
i += 1; i += match Opcode::from_u8((*haystack)[i]).classify() {
opcodes::PushBytes(n) => n,
opcodes::Ordinary(opcodes::OP_PUSHDATA1) => 2,
opcodes::Ordinary(opcodes::OP_PUSHDATA2) => 3,
opcodes::Ordinary(opcodes::OP_PUSHDATA4) => 5,
_ => 1
};
} }
} }
haystack.truncate(top + needle.len()); haystack.truncate(top + needle.len());
@ -106,39 +115,39 @@ pub fn find_and_remove<T:Eq+::std::fmt::Show>(haystack: &mut Vec<T>, needle: &[T
mod tests { mod tests {
use std::prelude::*; use std::prelude::*;
use super::find_and_remove; use super::script_find_and_remove;
use super::hex_bytes; use super::hex_bytes;
#[test] #[test]
fn test_find_and_remove() { fn test_script_find_and_remove() {
let mut v = vec![1u, 2, 3, 4, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9]; let mut v = vec![101u8, 102, 103, 104, 102, 103, 104, 102, 103, 104, 105, 106, 107, 108, 109];
assert_eq!(find_and_remove(&mut v, []), 0); assert_eq!(script_find_and_remove(&mut v, []), 0);
assert_eq!(find_and_remove(&mut v, [5, 5, 5]), 0); assert_eq!(script_find_and_remove(&mut v, [105, 105, 105]), 0);
assert_eq!(v, vec![1, 2, 3, 4, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9]); assert_eq!(v, vec![101, 102, 103, 104, 102, 103, 104, 102, 103, 104, 105, 106, 107, 108, 109]);
assert_eq!(find_and_remove(&mut v, [5, 6, 7]), 1); assert_eq!(script_find_and_remove(&mut v, [105, 106, 107]), 1);
assert_eq!(v, vec![1, 2, 3, 4, 2, 3, 4, 2, 3, 4, 8, 9]); assert_eq!(v, vec![101, 102, 103, 104, 102, 103, 104, 102, 103, 104, 108, 109]);
assert_eq!(find_and_remove(&mut v, [4, 8, 9]), 1); assert_eq!(script_find_and_remove(&mut v, [104, 108, 109]), 1);
assert_eq!(v, vec![1, 2, 3, 4, 2, 3, 4, 2, 3]); assert_eq!(v, vec![101, 102, 103, 104, 102, 103, 104, 102, 103]);
assert_eq!(find_and_remove(&mut v, [1]), 1); assert_eq!(script_find_and_remove(&mut v, [101]), 1);
assert_eq!(v, vec![2, 3, 4, 2, 3, 4, 2, 3]); assert_eq!(v, vec![102, 103, 104, 102, 103, 104, 102, 103]);
assert_eq!(find_and_remove(&mut v, [2]), 3); assert_eq!(script_find_and_remove(&mut v, [102]), 3);
assert_eq!(v, vec![3, 4, 3, 4, 3]); assert_eq!(v, vec![103, 104, 103, 104, 103]);
assert_eq!(find_and_remove(&mut v, [3, 4]), 2); assert_eq!(script_find_and_remove(&mut v, [103, 104]), 2);
assert_eq!(v, vec![3]); assert_eq!(v, vec![103]);
assert_eq!(find_and_remove(&mut v, [5, 5, 5]), 0); assert_eq!(script_find_and_remove(&mut v, [105, 105, 5]), 0);
assert_eq!(find_and_remove(&mut v, [5]), 0); assert_eq!(script_find_and_remove(&mut v, [105]), 0);
assert_eq!(find_and_remove(&mut v, [3]), 1); assert_eq!(script_find_and_remove(&mut v, [103]), 1);
assert_eq!(v, vec![]); assert_eq!(v, vec![]);
assert_eq!(find_and_remove(&mut v, [5, 5, 5]), 0); assert_eq!(script_find_and_remove(&mut v, [105, 105, 5]), 0);
assert_eq!(find_and_remove(&mut v, [5]), 0); assert_eq!(script_find_and_remove(&mut v, [105]), 0);
} }
#[test] #[test]