-
Notifications
You must be signed in to change notification settings - Fork 879
Description
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.
rust-bitcoin/bitcoin/src/crypto/sighash.rs
Lines 1361 to 1364 in 0157dc2
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.
rust-bitcoin/bitcoin/src/crypto/sighash.rs
Lines 1038 to 1044 in 0157dc2
/// 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. |