@@ -45,6 +45,14 @@ use VarInt;
45
45
#[ cfg( doc) ]
46
46
use util:: sighash:: SchnorrSigHashType ;
47
47
48
+ /// Used for signature hash for invalid use of SIGHASH_SINGLE.
49
+ const UINT256_ONE : [ u8 ; 32 ] = [
50
+ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
51
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
52
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
53
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
54
+ ] ;
55
+
48
56
/// A reference to a transaction output.
49
57
#[ derive( Copy , Clone , Debug , Eq , Hash , PartialEq , PartialOrd , Ord ) ]
50
58
pub struct OutPoint {
@@ -340,15 +348,6 @@ impl Transaction {
340
348
341
349
let ( sighash, anyone_can_pay) = EcdsaSigHashType :: from_u32_consensus ( sighash_type) . split_anyonecanpay_flag ( ) ;
342
350
343
- // Special-case sighash_single bug because this is easy enough.
344
- if sighash == EcdsaSigHashType :: Single && input_index >= self . output . len ( ) {
345
- writer. write_all ( & [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
346
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
347
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
348
- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ?;
349
- return Ok ( ( ) ) ;
350
- }
351
-
352
351
// Build tx to sign
353
352
let mut tx = Transaction {
354
353
version : self . version ,
@@ -404,12 +403,24 @@ impl Transaction {
404
403
script_pubkey : & Script ,
405
404
sighash_u32 : u32
406
405
) -> SigHash {
406
+ if self . is_invalid_use_of_sighash_single ( sighash_u32, input_index) {
407
+ return SigHash :: from_slice ( & UINT256_ONE ) . expect ( "const-size array" ) ;
408
+ }
409
+
407
410
let mut engine = SigHash :: engine ( ) ;
408
411
self . encode_signing_data_to ( & mut engine, input_index, script_pubkey, sighash_u32)
409
412
. expect ( "engines don't error" ) ;
410
413
SigHash :: from_engine ( engine)
411
414
}
412
415
416
+ /// The SIGHASH_SINGLE bug becomes exploitable when one tries to sign a transaction with
417
+ /// SIGHASH_SINGLE and there is not a corresponding output transaction with the same index as
418
+ /// the input transaction.
419
+ fn is_invalid_use_of_sighash_single ( & self , sighash : u32 , input_index : usize ) -> bool {
420
+ let ty = EcdsaSigHashType :: from_u32_consensus ( sighash) ;
421
+ ty == EcdsaSigHashType :: Single && input_index >= self . output . len ( )
422
+ }
423
+
413
424
/// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty
414
425
/// witness, this is simply the consensus-serialized size times 4. For transactions with a
415
426
/// witness, this is the non-witness consensus-serialized size multiplied by 3 plus the
0 commit comments