@@ -40,18 +40,11 @@ use crate::consensus::{encode, Decodable, Encodable};
40
40
use crate :: consensus:: encode:: MAX_VEC_SIZE ;
41
41
use crate :: hash_types:: { Sighash , Txid , Wtxid } ;
42
42
use crate :: VarInt ;
43
+ use crate :: util:: sighash:: UINT256_ONE ;
43
44
44
45
#[ cfg( doc) ]
45
46
use crate :: util:: sighash:: SchnorrSighashType ;
46
47
47
- /// Used for signature hash for invalid use of SIGHASH_SINGLE.
48
- const UINT256_ONE : [ u8 ; 32 ] = [
49
- 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
50
- 0 , 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
- ] ;
54
-
55
48
/// A reference to a transaction output.
56
49
///
57
50
/// ### Bitcoin Core References
@@ -262,6 +255,67 @@ impl Default for TxOut {
262
255
}
263
256
}
264
257
258
+ /// Result of [`Transaction::encode_signing_data_to`].
259
+ ///
260
+ /// This type forces the caller to handle SIGHASH_SINGLE bug case.
261
+ ///
262
+ /// This corner case can't be expressed using standard `Result`,
263
+ /// in a way that is both convenient and not-prone to accidental
264
+ /// mistakes (like calling `.expect("writer never fails")`).
265
+ #[ must_use]
266
+ pub enum EncodeSigningDataResult < E > {
267
+ /// Input data is an instance of `SIGHASH_SINGLE` bug
268
+ SighashSingleBug ,
269
+ /// Operation performed normally.
270
+ WriteResult ( Result < ( ) , E > ) ,
271
+ }
272
+
273
+ impl < E > EncodeSigningDataResult < E > {
274
+ /// Checks for SIGHASH_SINGLE bug returning error if the writer failed.
275
+ ///
276
+ /// This method is provided for easy and correct handling of the result because
277
+ /// SIGHASH_SINGLE bug is a special case that must not be ignored nor cause panicking.
278
+ /// Since the data is usually written directly into a hasher which never fails,
279
+ /// the recommended pattern to handle this is:
280
+ ///
281
+ /// ```rust
282
+ /// # use bitcoin::consensus::deserialize;
283
+ /// # use bitcoin::{Transaction, Sighash};
284
+ /// # use bitcoin_hashes::{Hash, hex::FromHex};
285
+ /// # let mut writer = Sighash::engine();
286
+ /// # let input_index = 0;
287
+ /// # let script_pubkey = bitcoin::Script::new();
288
+ /// # let sighash_u32 = 0u32;
289
+ /// # const SOME_TX: &'static str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
290
+ /// # let raw_tx = Vec::from_hex(SOME_TX).unwrap();
291
+ /// # let tx: Transaction = deserialize(&raw_tx).unwrap();
292
+ /// if tx.encode_signing_data_to(&mut writer, input_index, &script_pubkey, sighash_u32)
293
+ /// .is_sighash_single_bug()
294
+ /// .expect("writer can't fail") {
295
+ /// // use a hash value of "1", instead of computing the actual hash due to SIGHASH_SINGLE bug
296
+ /// }
297
+ /// ```
298
+ pub fn is_sighash_single_bug ( self ) -> Result < bool , E > {
299
+ match self {
300
+ EncodeSigningDataResult :: SighashSingleBug => Ok ( true ) ,
301
+ EncodeSigningDataResult :: WriteResult ( Ok ( ( ) ) ) => Ok ( false ) ,
302
+ EncodeSigningDataResult :: WriteResult ( Err ( e) ) => Err ( e) ,
303
+ }
304
+ }
305
+
306
+ /// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a
307
+ /// contained [`Err`] value, leaving an [`Ok`] value untouched.
308
+ ///
309
+ /// Like [`Result::map_err`].
310
+ pub fn map_err < E2 , F > ( self , f : F ) -> EncodeSigningDataResult < E2 > where F : FnOnce ( E ) -> E2 {
311
+ match self {
312
+ EncodeSigningDataResult :: SighashSingleBug => EncodeSigningDataResult :: SighashSingleBug ,
313
+ EncodeSigningDataResult :: WriteResult ( Err ( e) ) => EncodeSigningDataResult :: WriteResult ( Err ( f ( e) ) ) ,
314
+ EncodeSigningDataResult :: WriteResult ( Ok ( o) ) => EncodeSigningDataResult :: WriteResult ( Ok ( o) ) ,
315
+ }
316
+ }
317
+ }
318
+
265
319
/// Bitcoin transaction.
266
320
///
267
321
/// An authenticated movement of coins.
@@ -370,19 +424,23 @@ impl Transaction {
370
424
/// - Does NOT attempt to support OP_CODESEPARATOR. In general this would require evaluating
371
425
/// `script_pubkey` to determine which separators get evaluated and which don't, which we don't
372
426
/// have the information to determine.
373
- /// - Does NOT handle the sighash single bug, you should either handle that manually or use
374
- /// [`Self::signature_hash()`] instead.
427
+ /// - Does NOT handle the sighash single bug (see "Return type" section)
428
+ ///
429
+ /// # Return type
430
+ ///
431
+ /// This function can't handle the SIGHASH_SINGLE bug internally, so it returns [`EncodeSigningDataResult`]
432
+ /// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]).
375
433
///
376
434
/// # Panics
377
435
///
378
436
/// If `input_index` is out of bounds (greater than or equal to `self.input.len()`).
379
437
pub fn encode_signing_data_to < Write : io:: Write , U : Into < u32 > > (
380
438
& self ,
381
- mut writer : Write ,
439
+ writer : Write ,
382
440
input_index : usize ,
383
441
script_pubkey : & Script ,
384
442
sighash_type : U ,
385
- ) -> Result < ( ) , encode :: Error > {
443
+ ) -> EncodeSigningDataResult < io :: Error > {
386
444
let sighash_type: u32 = sighash_type. into ( ) ;
387
445
assert ! ( input_index < self . input. len( ) ) ; // Panic on OOB
388
446
@@ -391,56 +449,73 @@ impl Transaction {
391
449
// will result in the data written to the writer being hashed, however the correct
392
450
// handling of the SIGHASH_SINGLE bug is to return the 'one array' - either implement
393
451
// this behaviour manually or use `signature_hash()`.
394
- writer. write_all ( b"[not a transaction] SIGHASH_SINGLE bug" ) ?;
395
- return Ok ( ( ) )
452
+ return EncodeSigningDataResult :: SighashSingleBug ;
396
453
}
397
454
398
- let ( sighash, anyone_can_pay) = EcdsaSighashType :: from_consensus ( sighash_type) . split_anyonecanpay_flag ( ) ;
399
-
400
- // Build tx to sign
401
- let mut tx = Transaction {
402
- version : self . version ,
403
- lock_time : self . lock_time ,
404
- input : vec ! [ ] ,
405
- output : vec ! [ ] ,
406
- } ;
407
- // Add all inputs necessary..
408
- if anyone_can_pay {
409
- tx. input = vec ! [ TxIn {
410
- previous_output: self . input[ input_index] . previous_output,
411
- script_sig: script_pubkey. clone( ) ,
412
- sequence: self . input[ input_index] . sequence,
413
- witness: Witness :: default ( ) ,
414
- } ] ;
415
- } else {
416
- tx. input = Vec :: with_capacity ( self . input . len ( ) ) ;
417
- for ( n, input) in self . input . iter ( ) . enumerate ( ) {
418
- tx. input . push ( TxIn {
419
- previous_output : input. previous_output ,
420
- script_sig : if n == input_index { script_pubkey. clone ( ) } else { Script :: new ( ) } ,
421
- sequence : if n != input_index && ( sighash == EcdsaSighashType :: Single || sighash == EcdsaSighashType :: None ) { 0 } else { input. sequence } ,
455
+ fn encode_signing_data_to_inner < Write : io:: Write > (
456
+ self_ : & Transaction ,
457
+ mut writer : Write ,
458
+ input_index : usize ,
459
+ script_pubkey : & Script ,
460
+ sighash_type : u32 ,
461
+ ) -> Result < ( ) , io:: Error > {
462
+ let ( sighash, anyone_can_pay) = EcdsaSighashType :: from_consensus ( sighash_type) . split_anyonecanpay_flag ( ) ;
463
+
464
+ // Build tx to sign
465
+ let mut tx = Transaction {
466
+ version : self_. version ,
467
+ lock_time : self_. lock_time ,
468
+ input : vec ! [ ] ,
469
+ output : vec ! [ ] ,
470
+ } ;
471
+ // Add all inputs necessary..
472
+ if anyone_can_pay {
473
+ tx. input = vec ! [ TxIn {
474
+ previous_output: self_. input[ input_index] . previous_output,
475
+ script_sig: script_pubkey. clone( ) ,
476
+ sequence: self_. input[ input_index] . sequence,
422
477
witness: Witness :: default ( ) ,
423
- } ) ;
478
+ } ] ;
479
+ } else {
480
+ tx. input = Vec :: with_capacity ( self_. input . len ( ) ) ;
481
+ for ( n, input) in self_. input . iter ( ) . enumerate ( ) {
482
+ tx. input . push ( TxIn {
483
+ previous_output : input. previous_output ,
484
+ script_sig : if n == input_index { script_pubkey. clone ( ) } else { Script :: new ( ) } ,
485
+ sequence : if n != input_index && ( sighash == EcdsaSighashType :: Single || sighash == EcdsaSighashType :: None ) { 0 } else { input. sequence } ,
486
+ witness : Witness :: default ( ) ,
487
+ } ) ;
488
+ }
424
489
}
490
+ // ..then all outputs
491
+ tx. output = match sighash {
492
+ EcdsaSighashType :: All => self_. output . clone ( ) ,
493
+ EcdsaSighashType :: Single => {
494
+ let output_iter = self_. output . iter ( )
495
+ . take ( input_index + 1 ) // sign all outputs up to and including this one, but erase
496
+ . enumerate ( ) // all of them except for this one
497
+ . map ( |( n, out) | if n == input_index { out. clone ( ) } else { TxOut :: default ( ) } ) ;
498
+ output_iter. collect ( )
499
+ }
500
+ EcdsaSighashType :: None => vec ! [ ] ,
501
+ _ => unreachable ! ( )
502
+ } ;
503
+ // hash the result
504
+ tx. consensus_encode ( & mut writer) ?;
505
+ let sighash_arr = endian:: u32_to_array_le ( sighash_type) ;
506
+ sighash_arr. consensus_encode ( & mut writer) ?;
507
+ Ok ( ( ) )
425
508
}
426
- // ..then all outputs
427
- tx. output = match sighash {
428
- EcdsaSighashType :: All => self . output . clone ( ) ,
429
- EcdsaSighashType :: Single => {
430
- let output_iter = self . output . iter ( )
431
- . take ( input_index + 1 ) // sign all outputs up to and including this one, but erase
432
- . enumerate ( ) // all of them except for this one
433
- . map ( |( n, out) | if n == input_index { out. clone ( ) } else { TxOut :: default ( ) } ) ;
434
- output_iter. collect ( )
435
- }
436
- EcdsaSighashType :: None => vec ! [ ] ,
437
- _ => unreachable ! ( )
438
- } ;
439
- // hash the result
440
- tx. consensus_encode ( & mut writer) ?;
441
- let sighash_arr = endian:: u32_to_array_le ( sighash_type) ;
442
- sighash_arr. consensus_encode ( & mut writer) ?;
443
- Ok ( ( ) )
509
+
510
+ EncodeSigningDataResult :: WriteResult (
511
+ encode_signing_data_to_inner (
512
+ self ,
513
+ writer,
514
+ input_index,
515
+ script_pubkey,
516
+ sighash_type
517
+ )
518
+ )
444
519
}
445
520
446
521
/// Computes a signature hash for a given input index with a given sighash flag.
@@ -473,12 +548,15 @@ impl Transaction {
473
548
sighash_u32 : u32
474
549
) -> Sighash {
475
550
if self . is_invalid_use_of_sighash_single ( sighash_u32, input_index) {
476
- return Sighash :: from_slice ( & UINT256_ONE ) . expect ( "const-size array" ) ;
551
+ return Sighash :: from_inner ( UINT256_ONE ) ;
477
552
}
478
553
479
554
let mut engine = Sighash :: engine ( ) ;
480
- self . encode_signing_data_to ( & mut engine, input_index, script_pubkey, sighash_u32)
481
- . expect ( "engines don't error" ) ;
555
+ if self . encode_signing_data_to ( & mut engine, input_index, script_pubkey, sighash_u32)
556
+ . is_sighash_single_bug ( )
557
+ . expect ( "engines don't error" ) {
558
+ return Sighash :: from_slice ( & UINT256_ONE ) . expect ( "const-size array" ) ;
559
+ }
482
560
Sighash :: from_engine ( engine)
483
561
}
484
562
0 commit comments