Use 1 signature hash for invalid SIGHASH_SINGLE
When signing a transaction will result in the sighash single bug being exploitable we should return the 1 array (equivalent to 1 as a uint256) as the signature hash. Currently we are using the correct array value but are re-hashing it, instead we should directly return it.
This commit is contained in:
parent
3831816a73
commit
82f29b4267
|
@ -45,6 +45,14 @@ use VarInt;
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use util::sighash::SchnorrSigHashType;
|
use util::sighash::SchnorrSigHashType;
|
||||||
|
|
||||||
|
/// Used for signature hash for invalid use of SIGHASH_SINGLE.
|
||||||
|
const UINT256_ONE: [u8; 32] = [
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
];
|
||||||
|
|
||||||
/// A reference to a transaction output.
|
/// A reference to a transaction output.
|
||||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct OutPoint {
|
pub struct OutPoint {
|
||||||
|
@ -340,15 +348,6 @@ impl Transaction {
|
||||||
|
|
||||||
let (sighash, anyone_can_pay) = EcdsaSigHashType::from_u32_consensus(sighash_type).split_anyonecanpay_flag();
|
let (sighash, anyone_can_pay) = EcdsaSigHashType::from_u32_consensus(sighash_type).split_anyonecanpay_flag();
|
||||||
|
|
||||||
// Special-case sighash_single bug because this is easy enough.
|
|
||||||
if sighash == EcdsaSigHashType::Single && input_index >= self.output.len() {
|
|
||||||
writer.write_all(&[1, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0])?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build tx to sign
|
// Build tx to sign
|
||||||
let mut tx = Transaction {
|
let mut tx = Transaction {
|
||||||
version: self.version,
|
version: self.version,
|
||||||
|
@ -404,12 +403,24 @@ impl Transaction {
|
||||||
script_pubkey: &Script,
|
script_pubkey: &Script,
|
||||||
sighash_u32: u32
|
sighash_u32: u32
|
||||||
) -> SigHash {
|
) -> SigHash {
|
||||||
|
if self.is_invalid_use_of_sighash_single(sighash_u32, input_index) {
|
||||||
|
return SigHash::from_slice(&UINT256_ONE).expect("const-size array");
|
||||||
|
}
|
||||||
|
|
||||||
let mut engine = SigHash::engine();
|
let mut engine = SigHash::engine();
|
||||||
self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32)
|
self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32)
|
||||||
.expect("engines don't error");
|
.expect("engines don't error");
|
||||||
SigHash::from_engine(engine)
|
SigHash::from_engine(engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The SIGHASH_SINGLE bug becomes exploitable when one tries to sign a transaction with
|
||||||
|
/// SIGHASH_SINGLE and there is not a corresponding output transaction with the same index as
|
||||||
|
/// the input transaction.
|
||||||
|
fn is_invalid_use_of_sighash_single(&self, sighash: u32, input_index: usize) -> bool {
|
||||||
|
let ty = EcdsaSigHashType::from_u32_consensus(sighash);
|
||||||
|
ty == EcdsaSigHashType::Single && input_index >= self.output.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty
|
/// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty
|
||||||
/// witness, this is simply the consensus-serialized size times 4. For transactions with a
|
/// witness, this is simply the consensus-serialized size times 4. For transactions with a
|
||||||
/// witness, this is the non-witness consensus-serialized size multiplied by 3 plus the
|
/// witness, this is the non-witness consensus-serialized size multiplied by 3 plus the
|
||||||
|
|
Loading…
Reference in New Issue