From 0e1d927b471d44082582ba720dda2a47108c035a Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 26 Mar 2018 13:51:46 -0400 Subject: [PATCH] Only provide the required TxIn to bip143 sighash_all. This resolves an very unergonomic API by allowing iteration over a Transaction being signed's inputs without needing to take a conflicting reference to the transaction. The API is still relateively unsafe in that its very easy to generate bogus sighashes with it, but this is much better than it was, and its not clear how to fix it further. --- src/util/bip143.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/util/bip143.rs b/src/util/bip143.rs index 9e3f6bca..6d500977 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -20,7 +20,7 @@ //! use blockdata::script::Script; -use blockdata::transaction::Transaction; +use blockdata::transaction::{Transaction, TxIn}; use network::encodable::ConsensusEncodable; use util::hash::{Sha256dHash, Sha256dEncoder}; @@ -28,6 +28,8 @@ use util::hash::{Sha256dHash, Sha256dEncoder}; /// sufficient (in conjunction with a private key) to sign the transaction #[derive(Clone, PartialEq, Eq, Debug)] pub struct SighashComponents { + tx_version: u32, + tx_locktime: u32, /// Hash of all the previous outputs pub hash_prevouts: Sha256dHash, /// Hash of all the input sequence nos @@ -38,7 +40,9 @@ pub struct SighashComponents { impl SighashComponents { /// Compute the sighash components from an unsigned transaction and auxiliary - /// information about its inputs + /// information about its inputs. + /// For the generated sighashes to be valid, no fields in the transaction may change except for + /// script_sig and witnesses. pub fn new(tx: &Transaction) -> SighashComponents { let hash_prevouts = { let mut enc = Sha256dEncoder::new(); @@ -66,6 +70,8 @@ impl SighashComponents { }; SighashComponents { + tx_version: tx.version, + tx_locktime: tx.lock_time, hash_prevouts: hash_prevouts, hash_sequence: hash_sequence, hash_outputs: hash_outputs, @@ -73,25 +79,25 @@ impl SighashComponents { } /// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given - /// input index - pub fn sighash_all(&self, tx: &Transaction, index: usize, witness_script: &Script, value: u64) -> Sha256dHash { + /// input. + pub fn sighash_all(&self, txin: &TxIn, witness_script: &Script, value: u64) -> Sha256dHash { let mut enc = Sha256dEncoder::new(); - tx.version.consensus_encode(&mut enc).unwrap(); + self.tx_version.consensus_encode(&mut enc).unwrap(); self.hash_prevouts.consensus_encode(&mut enc).unwrap(); self.hash_sequence.consensus_encode(&mut enc).unwrap(); - tx.input[index] + txin .prev_hash .consensus_encode(&mut enc) .unwrap(); - tx.input[index] + txin .prev_index .consensus_encode(&mut enc) .unwrap(); witness_script.consensus_encode(&mut enc).unwrap(); value.consensus_encode(&mut enc).unwrap(); - tx.input[index].sequence.consensus_encode(&mut enc).unwrap(); + txin.sequence.consensus_encode(&mut enc).unwrap(); self.hash_outputs.consensus_encode(&mut enc).unwrap(); - tx.lock_time.consensus_encode(&mut enc).unwrap(); + self.tx_locktime.consensus_encode(&mut enc).unwrap(); 1u32.consensus_encode(&mut enc).unwrap(); // hashtype enc.into_hash() } @@ -130,6 +136,8 @@ mod tests { assert_eq!( comp, SighashComponents { + tx_version: 1, + tx_locktime: 0, hash_prevouts: hex_hash!( "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0" ), @@ -143,7 +151,7 @@ mod tests { ); assert_eq!( - comp.sighash_all(&tx, 0, &witness_script, value), + comp.sighash_all(&tx.input[0], &witness_script, value), hex_hash!("185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c") ); }