From 41e447172175a55c1e1274179486fc58fe82a84e Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 8 Apr 2020 14:35:48 +0300 Subject: [PATCH 1/3] Remove alloc when hashing sighash --- src/blockdata/transaction.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 99b87f22..f24d8727 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -33,7 +33,7 @@ use util::endian; use blockdata::constants::WITNESS_SCALE_FACTOR; #[cfg(feature="bitcoinconsensus")] use blockdata::script; use blockdata::script::Script; -use consensus::{encode, serialize, Decodable, Encodable}; +use consensus::{encode, Decodable, Encodable}; use hash_types::*; use VarInt; @@ -378,9 +378,12 @@ impl Transaction { _ => unreachable!() }; // hash the result - let mut raw_vec = serialize(&tx); - raw_vec.extend_from_slice(&endian::u32_to_array_le(sighash_u32)); - SigHash::hash(&raw_vec) + // TODO: Sanity assert that consensus_encode returned length matches the hashed length in the hasher. + let sighash_arr = endian::u32_to_array_le(sighash_u32); + let mut engine = SigHash::engine(); + tx.consensus_encode(&mut engine).unwrap(); + sighash_arr.consensus_encode(&mut engine).unwrap(); + SigHash::from_engine(engine) } /// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty @@ -441,7 +444,7 @@ impl Transaction { /// The lambda spent should not return the same TxOut twice! pub fn verify(&self, mut spent: S) -> Result<(), script::Error> where S: FnMut(&OutPoint) -> Option { - let tx = serialize(&*self); + let tx = encode::serialize(&*self); for (idx, input) in self.input.iter().enumerate() { if let Some(output) = spent(&input.previous_output) { output.script_pubkey.verify(idx, output.value, tx.as_slice())?; From 25cb3d3539306a075cf434bfe947e98e16a19a66 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 8 Apr 2020 15:01:47 +0300 Subject: [PATCH 2/3] Remove alloc when hashing for Bitcoin message signing format --- src/util/misc.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/util/misc.rs b/src/util/misc.rs index 2ee4fb0c..5a925e34 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -16,9 +16,9 @@ //! //! Various utility functions -use hashes::{sha256d, Hash}; +use hashes::{sha256d, Hash, HashEngine}; use blockdata::opcodes; -use consensus::encode; +use consensus::{encode, Encodable}; static MSG_SIGN_PREFIX: &[u8] = b"\x18Bitcoin Signed Message:\n"; @@ -59,14 +59,15 @@ pub fn script_find_and_remove(haystack: &mut Vec, needle: &[u8]) -> usize { /// Hash message for signature using Bitcoin's message signing format pub fn signed_msg_hash(msg: &str) -> sha256d::Hash { - sha256d::Hash::hash( - &[ - MSG_SIGN_PREFIX, - &encode::serialize(&encode::VarInt(msg.len() as u64)), - msg.as_bytes(), - ] - .concat(), - ) + let msg_len = encode::VarInt(msg.len() as u64); + + // TODO: Sanity assert that consensus_encode returned length matches the hashed length in the hasher. + let mut engine = sha256d::Hash::engine(); + engine.input(MSG_SIGN_PREFIX); + msg_len.consensus_encode(&mut engine).unwrap(); + engine.input(msg.as_bytes()); + + sha256d::Hash::from_engine(engine) } #[cfg(test)] From af31017eb19cadc8072a5efb7cf3f596b2d40bab Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 12 Apr 2020 19:00:55 +0300 Subject: [PATCH 3/3] Remove the cursor overhead, write is implemented on vec these days --- src/blockdata/transaction.rs | 3 +-- src/consensus/encode.rs | 6 +++--- src/util/misc.rs | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index f24d8727..1317032d 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -378,10 +378,9 @@ impl Transaction { _ => unreachable!() }; // hash the result - // TODO: Sanity assert that consensus_encode returned length matches the hashed length in the hasher. - let sighash_arr = endian::u32_to_array_le(sighash_u32); let mut engine = SigHash::engine(); tx.consensus_encode(&mut engine).unwrap(); + let sighash_arr = endian::u32_to_array_le(sighash_u32); sighash_arr.consensus_encode(&mut engine).unwrap(); SigHash::from_engine(engine) } diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index e3a38396..d6dbcb4b 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -149,10 +149,10 @@ impl From for Error { /// Encode an object into a vector pub fn serialize(data: &T) -> Vec { - let mut encoder = Cursor::new(vec![]); + let mut encoder = Vec::new(); let len = data.consensus_encode(&mut encoder).unwrap(); - assert_eq!(len, encoder.get_ref().len()); - encoder.into_inner() + assert_eq!(len, encoder.len()); + encoder } /// Encode an object into a hex-encoded string diff --git a/src/util/misc.rs b/src/util/misc.rs index 5a925e34..98e0f709 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -59,11 +59,10 @@ pub fn script_find_and_remove(haystack: &mut Vec, needle: &[u8]) -> usize { /// Hash message for signature using Bitcoin's message signing format pub fn signed_msg_hash(msg: &str) -> sha256d::Hash { - let msg_len = encode::VarInt(msg.len() as u64); - // TODO: Sanity assert that consensus_encode returned length matches the hashed length in the hasher. let mut engine = sha256d::Hash::engine(); engine.input(MSG_SIGN_PREFIX); + let msg_len = encode::VarInt(msg.len() as u64); msg_len.consensus_encode(&mut engine).unwrap(); engine.input(msg.as_bytes());