Skip to content

is_invalid_use_of_sighash_single() incompatibility with Bitcoin Core #4112

@liuchengxu

Description

@liuchengxu

Currently, the function is_invalid_use_of_sighash_single() is incompatible with Bitcoin Core’s implementation. I discovered this issue while working on an experimental Rust Bitcoin script interpreter, where it failed to verify the signature for the following transaction input using the sighash calculated from legacy_signature_hash():

block_number: 479902, 
tx_index: 1139, 
txid: 1395dde8ec0152f4cb090f4d4e8dcb14cc0d8bbba780e686c44934370cd316ec
input_index: 2

sighash for this specific input is 131(0x83), input_index is 2, outputs_len is 2, it's a single sighash bug per Bitcoin Core.

fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool {
let ty = EcdsaSighashType::from_consensus(sighash);
ty == EcdsaSighashType::Single && input_index >= outputs_len
}

However, 131 is interpreted as EcdsaSighashType::SinglePlusAnyoneCanPay here, is_invalid_use_of_sighash_single() handles EcdsaSighashType::Single only, thus it's not considered as sighash_single_bug and legavy_signature_hash() does not return the expected sighash ONE.

This results in an incorrect outcome that diverges from Bitcoin Core’s behavior, and makes the comment in legacy_signature_hash() misleading, as it claims the behavior is compatible.

/// The `sighash_type` supports an arbitrary `u32` value, instead of just [`EcdsaSighashType`],
/// because internally 4 bytes are being hashed, even though only the lowest byte is appended to
/// signature in a transaction.
///
/// This function correctly handles the sighash single bug by returning the 'one array'. The
/// sighash single bug becomes exploitable when one tries to sign a transaction with
/// `SIGHASH_SINGLE` and there is not a corresponding output with the same index as the input.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions