2021-03-03 13:22:05 -08:00
// Bitcoin Dev Kit
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
2020-08-31 11:26:36 +02:00
//
2021-03-03 13:22:05 -08:00
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
2020-08-31 11:26:36 +02:00
//
2021-03-03 13:22:05 -08:00
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
2020-08-31 11:26:36 +02:00
2020-09-04 15:45:11 +02:00
//! Generalized signers
//!
//! This module provides the ability to add customized signers to a [`Wallet`](super::Wallet)
//! through the [`Wallet::add_signer`](super::Wallet::add_signer) function.
//!
//! ```
//! # use std::sync::Arc;
//! # use std::str::FromStr;
2020-11-16 22:07:38 +01:00
//! # use bitcoin::secp256k1::{Secp256k1, All};
2020-09-04 15:45:11 +02:00
//! # use bitcoin::*;
//! # use bitcoin::util::psbt;
2020-09-14 14:25:38 +02:00
//! # use bdk::signer::*;
//! # use bdk::database::*;
//! # use bdk::*;
2020-09-04 15:45:11 +02:00
//! # #[derive(Debug)]
//! # struct CustomHSM;
//! # impl CustomHSM {
//! # fn sign_input(&self, _psbt: &mut psbt::PartiallySignedTransaction, _input: usize) -> Result<(), SignerError> {
//! # Ok(())
//! # }
//! # fn connect() -> Self {
//! # CustomHSM
//! # }
2021-01-25 15:04:56 -05:00
//! # fn get_id(&self) -> SignerId {
//! # SignerId::Dummy(0)
//! # }
2020-09-04 15:45:11 +02:00
//! # }
//! #[derive(Debug)]
//! struct CustomSigner {
//! device: CustomHSM,
//! }
//!
//! impl CustomSigner {
//! fn connect() -> Self {
//! CustomSigner { device: CustomHSM::connect() }
//! }
//! }
//!
//! impl Signer for CustomSigner {
//! fn sign(
//! &self,
//! psbt: &mut psbt::PartiallySignedTransaction,
//! input_index: Option<usize>,
2020-11-16 22:07:38 +01:00
//! _secp: &Secp256k1<All>,
2020-09-04 15:45:11 +02:00
//! ) -> Result<(), SignerError> {
//! let input_index = input_index.ok_or(SignerError::InputIndexOutOfRange)?;
//! self.device.sign_input(psbt, input_index)?;
//!
//! Ok(())
//! }
//!
2021-01-25 15:04:56 -05:00
//! fn id(&self, _secp: &Secp256k1<All>) -> SignerId {
//! self.device.get_id()
//! }
//!
2020-09-04 15:45:11 +02:00
//! fn sign_whole_tx(&self) -> bool {
//! false
//! }
//! }
//!
//! let custom_signer = CustomSigner::connect();
//!
//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
2022-01-26 15:17:48 +11:00
//! let mut wallet = Wallet::new(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
2020-09-04 15:45:11 +02:00
//! wallet.add_signer(
2020-12-14 17:14:24 +01:00
//! KeychainKind::External,
2020-09-04 15:45:11 +02:00
//! SignerOrdering(200),
2020-11-03 16:03:44 +11:00
//! Arc::new(custom_signer)
2020-09-04 15:45:11 +02:00
//! );
//!
2020-09-14 14:25:38 +02:00
//! # Ok::<_, bdk::Error>(())
2020-09-04 15:45:11 +02:00
//! ```
2020-08-17 12:10:51 +02:00
use std ::cmp ::Ordering ;
2020-12-14 17:50:47 +07:00
use std ::collections ::BTreeMap ;
2020-08-12 12:51:50 +02:00
use std ::fmt ;
2020-12-14 17:50:47 +07:00
use std ::ops ::Bound ::Included ;
2020-08-15 23:21:13 +02:00
use std ::sync ::Arc ;
2020-08-12 12:51:50 +02:00
use bitcoin ::blockdata ::opcodes ;
use bitcoin ::blockdata ::script ::Builder as ScriptBuilder ;
use bitcoin ::hashes ::{ hash160 , Hash } ;
use bitcoin ::secp256k1 ::{ Message , Secp256k1 } ;
2021-03-11 17:39:02 -05:00
use bitcoin ::util ::bip32 ::{ ChildNumber , DerivationPath , ExtendedPrivKey , Fingerprint } ;
2020-08-12 12:51:50 +02:00
use bitcoin ::util ::{ bip143 , psbt } ;
2020-09-16 17:31:43 +02:00
use bitcoin ::{ PrivateKey , Script , SigHash , SigHashType } ;
2020-08-12 12:51:50 +02:00
2020-10-09 12:03:47 +02:00
use miniscript ::descriptor ::{ DescriptorSecretKey , DescriptorSinglePriv , DescriptorXKey , KeyMap } ;
2020-08-12 12:51:50 +02:00
use miniscript ::{ Legacy , MiniscriptKey , Segwitv0 } ;
2020-11-16 22:07:38 +01:00
use super ::utils ::SecpCtx ;
2020-08-12 12:51:50 +02:00
use crate ::descriptor ::XKeyUtils ;
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
2020-09-04 15:45:11 +02:00
/// multiple of them
2020-12-15 11:33:33 +07:00
#[ derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Hash) ]
2020-10-09 12:03:47 +02:00
pub enum SignerId {
2020-12-11 14:10:11 -08:00
/// Bitcoin HASH160 (RIPEMD160 after SHA256) hash of an ECDSA public key
2020-10-09 12:03:47 +02:00
PkHash ( hash160 ::Hash ) ,
2020-12-11 14:10:11 -08:00
/// The fingerprint of a BIP32 extended key
2020-08-12 12:51:50 +02:00
Fingerprint ( Fingerprint ) ,
2021-01-25 15:04:56 -05:00
/// Dummy identifier
Dummy ( u64 ) ,
2020-08-12 12:51:50 +02:00
}
2020-10-09 12:03:47 +02:00
impl From < hash160 ::Hash > for SignerId {
fn from ( hash : hash160 ::Hash ) -> SignerId {
2020-08-12 12:51:50 +02:00
SignerId ::PkHash ( hash )
}
}
2020-10-09 12:03:47 +02:00
impl From < Fingerprint > for SignerId {
fn from ( fing : Fingerprint ) -> SignerId {
2020-08-12 12:51:50 +02:00
SignerId ::Fingerprint ( fing )
}
}
/// Signing error
#[ derive(Debug, PartialEq, Eq, Clone) ]
pub enum SignerError {
/// The private key is missing for the required public key
MissingKey ,
2020-09-29 18:18:50 +02:00
/// The private key in use has the right fingerprint but derives differently than expected
InvalidKey ,
2020-08-12 12:51:50 +02:00
/// The user canceled the operation
UserCanceled ,
/// Input index is out of range
InputIndexOutOfRange ,
/// The `non_witness_utxo` field of the transaction is required to sign this input
MissingNonWitnessUtxo ,
/// The `non_witness_utxo` specified is invalid
InvalidNonWitnessUtxo ,
/// The `witness_utxo` field of the transaction is required to sign this input
MissingWitnessUtxo ,
2021-11-23 13:40:58 -05:00
/// The `witness_script` field of the transaction is required to sign this input
2020-08-12 12:51:50 +02:00
MissingWitnessScript ,
/// The fingerprint and derivation path are missing from the psbt input
2021-03-30 16:33:07 +02:00
MissingHdKeypath ,
2021-05-26 10:34:25 +02:00
/// The psbt contains a non-`SIGHASH_ALL` sighash in one of its input and the user hasn't
/// explicitly allowed them
///
/// To enable signing transactions with non-standard sighashes set
/// [`SignOptions::allow_all_sighashes`] to `true`.
NonStandardSighash ,
2020-08-12 12:51:50 +02:00
}
2020-08-31 10:49:44 +02:00
impl fmt ::Display for SignerError {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
write! ( f , " {:?} " , self )
}
}
impl std ::error ::Error for SignerError { }
2020-08-12 12:51:50 +02:00
/// Trait for signers
2020-09-04 15:45:11 +02:00
///
/// This trait can be implemented to provide customized signers to the wallet. For an example see
/// [`this module`](crate::wallet::signer)'s documentation.
2020-11-03 16:06:03 +11:00
pub trait Signer : fmt ::Debug + Send + Sync {
2020-09-04 15:45:11 +02:00
/// Sign a PSBT
///
/// The `input_index` argument is only provided if the wallet doesn't declare to sign the whole
/// transaction in one go (see [`Signer::sign_whole_tx`]). Otherwise its value is `None` and
/// can be ignored.
2020-08-12 12:51:50 +02:00
fn sign (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
2020-08-17 23:50:50 +02:00
input_index : Option < usize > ,
2020-11-16 22:07:38 +01:00
secp : & SecpCtx ,
2020-08-12 12:51:50 +02:00
) -> Result < ( ) , SignerError > ;
2020-09-04 15:45:11 +02:00
/// Return whether or not the signer signs the whole transaction in one go instead of every
/// input individually
2020-08-31 10:49:44 +02:00
fn sign_whole_tx ( & self ) -> bool ;
2020-08-17 23:50:50 +02:00
2021-01-25 15:04:56 -05:00
/// Return the [`SignerId`] for this signer
///
/// The [`SignerId`] can be used to lookup a signer in the [`Wallet`](crate::Wallet)'s signers map or to
/// compare two signers.
fn id ( & self , secp : & SecpCtx ) -> SignerId ;
2020-09-04 15:45:11 +02:00
/// Return the secret key for the signer
///
/// This is used internally to reconstruct the original descriptor that may contain secrets.
/// External signers that are meant to keep key isolated should just return `None` here (which
/// is the default for this method, if not overridden).
2020-08-12 12:51:50 +02:00
fn descriptor_secret_key ( & self ) -> Option < DescriptorSecretKey > {
None
}
}
impl Signer for DescriptorXKey < ExtendedPrivKey > {
fn sign (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
2020-08-17 23:50:50 +02:00
input_index : Option < usize > ,
2020-11-16 22:07:38 +01:00
secp : & SecpCtx ,
2020-08-12 12:51:50 +02:00
) -> Result < ( ) , SignerError > {
2020-08-17 23:50:50 +02:00
let input_index = input_index . unwrap ( ) ;
2020-08-12 12:51:50 +02:00
if input_index > = psbt . inputs . len ( ) {
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
2021-05-06 17:11:43 +02:00
if psbt . inputs [ input_index ] . final_script_sig . is_some ( )
| | psbt . inputs [ input_index ] . final_script_witness . is_some ( )
{
return Ok ( ( ) ) ;
}
2021-03-11 17:39:02 -05:00
let ( public_key , full_path ) = match psbt . inputs [ input_index ]
2021-02-02 20:06:40 -05:00
. bip32_derivation
2020-08-12 12:51:50 +02:00
. iter ( )
2020-09-29 18:18:50 +02:00
. filter_map ( | ( pk , & ( fingerprint , ref path ) ) | {
2021-06-08 13:57:55 +10:00
if self . matches ( & ( fingerprint , path . clone ( ) ) , secp ) . is_some ( ) {
2020-09-29 18:18:50 +02:00
Some ( ( pk , path ) )
} else {
None
}
} )
2020-08-12 12:51:50 +02:00
. next ( )
{
2020-09-29 18:18:50 +02:00
Some ( ( pk , full_path ) ) = > ( pk , full_path . clone ( ) ) ,
None = > return Ok ( ( ) ) ,
2020-08-12 12:51:50 +02:00
} ;
2021-03-11 17:39:02 -05:00
let derived_key = match self . origin . clone ( ) {
2021-03-11 21:35:16 -05:00
Some ( ( _fingerprint , origin_path ) ) = > {
let deriv_path = DerivationPath ::from (
2021-03-11 21:54:00 -05:00
& full_path . into_iter ( ) . cloned ( ) . collect ::< Vec < ChildNumber > > ( )
[ origin_path . len ( ) .. ] ,
2021-03-11 21:35:16 -05:00
) ;
2021-06-08 13:57:55 +10:00
self . xkey . derive_priv ( secp , & deriv_path ) . unwrap ( )
2021-03-11 17:39:02 -05:00
}
2021-06-08 13:57:55 +10:00
None = > self . xkey . derive_priv ( secp , & full_path ) . unwrap ( ) ,
2021-03-11 17:39:02 -05:00
} ;
2021-06-08 13:57:55 +10:00
if & derived_key . private_key . public_key ( secp ) ! = public_key {
2020-09-29 18:18:50 +02:00
Err ( SignerError ::InvalidKey )
} else {
2020-11-16 22:07:38 +01:00
derived_key . private_key . sign ( psbt , Some ( input_index ) , secp )
2020-09-29 18:18:50 +02:00
}
2020-08-12 12:51:50 +02:00
}
2020-08-31 10:49:44 +02:00
fn sign_whole_tx ( & self ) -> bool {
false
}
2021-01-25 15:04:56 -05:00
fn id ( & self , secp : & SecpCtx ) -> SignerId {
2021-06-08 13:57:55 +10:00
SignerId ::from ( self . root_fingerprint ( secp ) )
2021-01-25 15:04:56 -05:00
}
2020-08-12 12:51:50 +02:00
fn descriptor_secret_key ( & self ) -> Option < DescriptorSecretKey > {
Some ( DescriptorSecretKey ::XPrv ( self . clone ( ) ) )
}
}
impl Signer for PrivateKey {
fn sign (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
2020-08-17 23:50:50 +02:00
input_index : Option < usize > ,
2020-11-16 22:07:38 +01:00
secp : & SecpCtx ,
2020-08-12 12:51:50 +02:00
) -> Result < ( ) , SignerError > {
2020-08-17 23:50:50 +02:00
let input_index = input_index . unwrap ( ) ;
2021-05-06 17:11:43 +02:00
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . global . unsigned_tx . input . len ( ) {
2020-08-12 12:51:50 +02:00
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
2021-05-06 17:11:43 +02:00
if psbt . inputs [ input_index ] . final_script_sig . is_some ( )
| | psbt . inputs [ input_index ] . final_script_witness . is_some ( )
{
return Ok ( ( ) ) ;
}
2021-06-08 13:57:55 +10:00
let pubkey = self . public_key ( secp ) ;
2020-08-12 12:51:50 +02:00
if psbt . inputs [ input_index ] . partial_sigs . contains_key ( & pubkey ) {
return Ok ( ( ) ) ;
}
// FIXME: use the presence of `witness_utxo` as an indication that we should make a bip143
2021-11-23 13:40:58 -05:00
// sig. Does this make sense? Should we add an extra argument to explicitly switch between
2020-08-12 12:51:50 +02:00
// these? The original idea was to declare sign() as sign<Ctx: ScriptContex>() and use Ctx,
// but that violates the rules for trait-objects, so we can't do it.
let ( hash , sighash ) = match psbt . inputs [ input_index ] . witness_utxo {
Some ( _ ) = > Segwitv0 ::sighash ( psbt , input_index ) ? ,
None = > Legacy ::sighash ( psbt , input_index ) ? ,
} ;
2020-11-16 22:07:38 +01:00
let signature = secp . sign (
2020-08-12 12:51:50 +02:00
& Message ::from_slice ( & hash . into_inner ( ) [ .. ] ) . unwrap ( ) ,
& self . key ,
) ;
let mut final_signature = Vec ::with_capacity ( 75 ) ;
final_signature . extend_from_slice ( & signature . serialize_der ( ) ) ;
final_signature . push ( sighash . as_u32 ( ) as u8 ) ;
psbt . inputs [ input_index ]
. partial_sigs
. insert ( pubkey , final_signature ) ;
Ok ( ( ) )
}
2020-08-31 10:49:44 +02:00
fn sign_whole_tx ( & self ) -> bool {
false
}
2021-01-25 15:04:56 -05:00
fn id ( & self , secp : & SecpCtx ) -> SignerId {
SignerId ::from ( self . public_key ( secp ) . to_pubkeyhash ( ) )
}
2020-08-12 12:51:50 +02:00
fn descriptor_secret_key ( & self ) -> Option < DescriptorSecretKey > {
2020-10-09 12:03:47 +02:00
Some ( DescriptorSecretKey ::SinglePriv ( DescriptorSinglePriv {
key : * self ,
origin : None ,
} ) )
2020-08-12 12:51:50 +02:00
}
}
2020-09-04 15:45:11 +02:00
/// Defines the order in which signers are called
///
/// The default value is `100`. Signers with an ordering above that will be called later,
/// and they will thus see the partial signatures added to the transaction once they get to sign
/// themselves.
2020-12-14 17:50:47 +07:00
#[ derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq) ]
2020-08-17 12:10:51 +02:00
pub struct SignerOrdering ( pub usize ) ;
impl std ::default ::Default for SignerOrdering {
fn default ( ) -> Self {
SignerOrdering ( 100 )
}
}
2020-12-14 17:50:47 +07:00
#[ derive(Debug, Clone) ]
2020-10-09 12:03:47 +02:00
struct SignersContainerKey {
id : SignerId ,
2020-08-17 12:10:51 +02:00
ordering : SignerOrdering ,
}
2020-10-09 12:03:47 +02:00
impl From < ( SignerId , SignerOrdering ) > for SignersContainerKey {
fn from ( tuple : ( SignerId , SignerOrdering ) ) -> Self {
2020-08-17 12:10:51 +02:00
SignersContainerKey {
id : tuple . 0 ,
ordering : tuple . 1 ,
}
}
}
2020-08-12 12:51:50 +02:00
/// Container for multiple signers
2020-08-15 23:21:13 +02:00
#[ derive(Debug, Default, Clone) ]
2020-12-14 17:50:47 +07:00
pub struct SignersContainer ( BTreeMap < SignersContainerKey , Arc < dyn Signer > > ) ;
2020-08-12 12:51:50 +02:00
2020-10-09 12:03:47 +02:00
impl SignersContainer {
2020-12-11 14:10:11 -08:00
/// Create a map of public keys to secret keys
2020-11-16 22:07:38 +01:00
pub fn as_key_map ( & self , secp : & SecpCtx ) -> KeyMap {
2020-08-12 12:51:50 +02:00
self . 0
. values ( )
. filter_map ( | signer | signer . descriptor_secret_key ( ) )
2020-11-16 22:07:38 +01:00
. filter_map ( | secret | secret . as_public ( secp ) . ok ( ) . map ( | public | ( public , secret ) ) )
2020-08-12 12:51:50 +02:00
. collect ( )
}
}
2020-10-09 12:03:47 +02:00
impl From < KeyMap > for SignersContainer {
fn from ( keymap : KeyMap ) -> SignersContainer {
2020-11-16 22:07:38 +01:00
let secp = Secp256k1 ::new ( ) ;
2020-08-12 12:51:50 +02:00
let mut container = SignersContainer ::new ( ) ;
for ( _ , secret ) in keymap {
2020-12-14 00:22:06 +07:00
match secret {
2020-10-09 12:03:47 +02:00
DescriptorSecretKey ::SinglePriv ( private_key ) = > container . add_external (
2021-01-25 15:04:56 -05:00
SignerId ::from ( private_key . key . public_key ( & secp ) . to_pubkeyhash ( ) ) ,
2020-08-17 12:10:51 +02:00
SignerOrdering ::default ( ) ,
2020-11-03 16:03:44 +11:00
Arc ::new ( private_key . key ) ,
2020-08-15 23:21:13 +02:00
) ,
DescriptorSecretKey ::XPrv ( xprv ) = > container . add_external (
2020-11-16 22:07:38 +01:00
SignerId ::from ( xprv . root_fingerprint ( & secp ) ) ,
2020-08-17 12:10:51 +02:00
SignerOrdering ::default ( ) ,
2020-11-03 16:03:44 +11:00
Arc ::new ( xprv ) ,
2020-08-12 12:51:50 +02:00
) ,
} ;
}
container
}
}
2020-10-09 12:03:47 +02:00
impl SignersContainer {
2020-08-12 12:51:50 +02:00
/// Default constructor
pub fn new ( ) -> Self {
2020-08-17 12:10:51 +02:00
SignersContainer ( Default ::default ( ) )
2020-08-12 12:51:50 +02:00
}
/// Adds an external signer to the container for the specified id. Optionally returns the
2020-12-14 00:22:06 +07:00
/// signer that was previously in the container, if any
2020-08-12 12:51:50 +02:00
pub fn add_external (
& mut self ,
2020-10-09 12:03:47 +02:00
id : SignerId ,
2020-08-17 12:10:51 +02:00
ordering : SignerOrdering ,
2020-11-03 16:03:44 +11:00
signer : Arc < dyn Signer > ,
) -> Option < Arc < dyn Signer > > {
2020-12-14 00:22:06 +07:00
self . 0. insert ( ( id , ordering ) . into ( ) , signer )
2020-08-12 12:51:50 +02:00
}
/// Removes a signer from the container and returns it
2020-11-03 16:03:44 +11:00
pub fn remove ( & mut self , id : SignerId , ordering : SignerOrdering ) -> Option < Arc < dyn Signer > > {
2020-08-17 12:10:51 +02:00
self . 0. remove ( & ( id , ordering ) . into ( ) )
2020-08-12 12:51:50 +02:00
}
/// Returns the list of identifiers of all the signers in the container
2020-10-09 12:03:47 +02:00
pub fn ids ( & self ) -> Vec < & SignerId > {
2020-08-17 12:10:51 +02:00
self . 0
. keys ( )
. map ( | SignersContainerKey { id , .. } | id )
. collect ( )
}
/// Returns the list of signers in the container, sorted by lowest to highest `ordering`
2020-11-03 16:03:44 +11:00
pub fn signers ( & self ) -> Vec < & Arc < dyn Signer > > {
2020-12-14 17:50:47 +07:00
self . 0. values ( ) . collect ( )
2020-08-12 12:51:50 +02:00
}
2020-08-17 12:10:51 +02:00
/// Finds the signer with lowest ordering for a given id in the container.
2020-11-03 16:03:44 +11:00
pub fn find ( & self , id : SignerId ) -> Option < & Arc < dyn Signer > > {
2020-12-14 00:43:07 +07:00
self . 0
2020-12-14 17:50:47 +07:00
. range ( (
Included ( & ( id . clone ( ) , SignerOrdering ( 0 ) ) . into ( ) ) ,
2020-12-15 11:33:57 +07:00
Included ( & ( id . clone ( ) , SignerOrdering ( usize ::MAX ) ) . into ( ) ) ,
2020-12-14 17:50:47 +07:00
) )
2020-12-15 11:33:57 +07:00
. filter ( | ( k , _ ) | k . id = = id )
2020-08-17 12:10:51 +02:00
. map ( | ( _ , v ) | v )
2020-12-14 17:50:47 +07:00
. next ( )
2020-08-12 12:51:50 +02:00
}
}
2021-04-19 14:16:39 +02:00
/// Options for a software signer
///
/// Adjust the behavior of our software signers and the way a transaction is finalized
#[ derive(Debug, Clone) ]
pub struct SignOptions {
/// Whether the signer should trust the `witness_utxo`, if the `non_witness_utxo` hasn't been
/// provided
///
/// Defaults to `false` to mitigate the "SegWit bug" which chould trick the wallet into
/// paying a fee larger than expected.
///
/// Some wallets, especially if relatively old, might not provide the `non_witness_utxo` for
/// SegWit transactions in the PSBT they generate: in those cases setting this to `true`
/// should correctly produce a signature, at the expense of an increased trust in the creator
/// of the PSBT.
///
/// For more details see: <https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd>
pub trust_witness_utxo : bool ,
/// Whether the wallet should assume a specific height has been reached when trying to finalize
/// a transaction
///
/// The wallet will only "use" a timelock to satisfy the spending policy of an input if the
/// timelock height has already been reached. This option allows overriding the "current height" to let the
/// wallet use timelocks in the future to spend a coin.
pub assume_height : Option < u32 > ,
2021-05-26 10:34:25 +02:00
/// Whether the signer should use the `sighash_type` set in the PSBT when signing, no matter
/// what its value is
///
/// Defaults to `false` which will only allow signing using `SIGHASH_ALL`.
pub allow_all_sighashes : bool ,
2021-04-19 14:16:39 +02:00
}
impl Default for SignOptions {
fn default ( ) -> Self {
SignOptions {
trust_witness_utxo : false ,
assume_height : None ,
2021-05-26 10:34:25 +02:00
allow_all_sighashes : false ,
2021-04-19 14:16:39 +02:00
}
}
}
2020-08-31 10:49:44 +02:00
pub ( crate ) trait ComputeSighash {
2020-08-12 12:51:50 +02:00
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
) -> Result < ( SigHash , SigHashType ) , SignerError > ;
}
impl ComputeSighash for Legacy {
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
) -> Result < ( SigHash , SigHashType ) , SignerError > {
2021-05-06 14:41:30 +02:00
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . global . unsigned_tx . input . len ( ) {
2020-08-12 12:51:50 +02:00
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
let psbt_input = & psbt . inputs [ input_index ] ;
let tx_input = & psbt . global . unsigned_tx . input [ input_index ] ;
2020-10-16 15:40:30 +02:00
let sighash = psbt_input . sighash_type . unwrap_or ( SigHashType ::All ) ;
2020-10-07 14:18:50 -07:00
let script = match psbt_input . redeem_script {
Some ( ref redeem_script ) = > redeem_script . clone ( ) ,
None = > {
2020-08-12 12:51:50 +02:00
let non_witness_utxo = psbt_input
. non_witness_utxo
. as_ref ( )
. ok_or ( SignerError ::MissingNonWitnessUtxo ) ? ;
let prev_out = non_witness_utxo
. output
. get ( tx_input . previous_output . vout as usize )
. ok_or ( SignerError ::InvalidNonWitnessUtxo ) ? ;
prev_out . script_pubkey . clone ( )
}
} ;
Ok ( (
psbt . global
. unsigned_tx
. signature_hash ( input_index , & script , sighash . as_u32 ( ) ) ,
sighash ,
) )
}
}
2020-09-16 17:31:43 +02:00
fn p2wpkh_script_code ( script : & Script ) -> Script {
ScriptBuilder ::new ( )
. push_opcode ( opcodes ::all ::OP_DUP )
. push_opcode ( opcodes ::all ::OP_HASH160 )
. push_slice ( & script [ 2 .. ] )
. push_opcode ( opcodes ::all ::OP_EQUALVERIFY )
. push_opcode ( opcodes ::all ::OP_CHECKSIG )
. into_script ( )
}
2020-08-12 12:51:50 +02:00
impl ComputeSighash for Segwitv0 {
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
) -> Result < ( SigHash , SigHashType ) , SignerError > {
2021-05-06 14:41:30 +02:00
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . global . unsigned_tx . input . len ( ) {
2020-08-12 12:51:50 +02:00
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
let psbt_input = & psbt . inputs [ input_index ] ;
2021-04-19 14:16:39 +02:00
let tx_input = & psbt . global . unsigned_tx . input [ input_index ] ;
2020-08-12 12:51:50 +02:00
2020-10-16 15:40:30 +02:00
let sighash = psbt_input . sighash_type . unwrap_or ( SigHashType ::All ) ;
2020-08-12 12:51:50 +02:00
2021-04-19 14:16:39 +02:00
// Always try first with the non-witness utxo
let utxo = if let Some ( prev_tx ) = & psbt_input . non_witness_utxo {
// Check the provided prev-tx
if prev_tx . txid ( ) ! = tx_input . previous_output . txid {
return Err ( SignerError ::InvalidNonWitnessUtxo ) ;
}
// The output should be present, if it's missing the `non_witness_utxo` is invalid
prev_tx
. output
. get ( tx_input . previous_output . vout as usize )
. ok_or ( SignerError ::InvalidNonWitnessUtxo ) ?
} else if let Some ( witness_utxo ) = & psbt_input . witness_utxo {
// Fallback to the witness_utxo. If we aren't allowed to use it, signing should fail
// before we get to this point
witness_utxo
} else {
// Nothing has been provided
return Err ( SignerError ::MissingNonWitnessUtxo ) ;
} ;
let value = utxo . value ;
2020-08-12 12:51:50 +02:00
2020-10-07 14:18:50 -07:00
let script = match psbt_input . witness_script {
Some ( ref witness_script ) = > witness_script . clone ( ) ,
None = > {
2021-04-19 14:16:39 +02:00
if utxo . script_pubkey . is_v0_p2wpkh ( ) {
p2wpkh_script_code ( & utxo . script_pubkey )
2020-09-16 17:31:43 +02:00
} else if psbt_input
. redeem_script
. as_ref ( )
. map ( Script ::is_v0_p2wpkh )
. unwrap_or ( false )
{
2021-06-08 13:57:55 +10:00
p2wpkh_script_code ( psbt_input . redeem_script . as_ref ( ) . unwrap ( ) )
2020-08-12 12:51:50 +02:00
} else {
return Err ( SignerError ::MissingWitnessScript ) ;
}
}
} ;
Ok ( (
bip143 ::SigHashCache ::new ( & psbt . global . unsigned_tx ) . signature_hash (
input_index ,
& script ,
value ,
sighash ,
) ,
sighash ,
) )
}
}
2020-08-17 12:10:51 +02:00
2020-10-09 12:03:47 +02:00
impl PartialOrd for SignersContainerKey {
2020-08-17 12:10:51 +02:00
fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
Some ( self . cmp ( other ) )
}
}
2020-10-09 12:03:47 +02:00
impl Ord for SignersContainerKey {
2020-08-17 12:10:51 +02:00
fn cmp ( & self , other : & Self ) -> Ordering {
2020-12-15 11:34:25 +07:00
self . ordering
. cmp ( & other . ordering )
. then ( self . id . cmp ( & other . id ) )
2020-08-17 12:10:51 +02:00
}
}
2020-12-14 00:22:22 +07:00
2020-12-14 17:50:47 +07:00
impl PartialEq for SignersContainerKey {
fn eq ( & self , other : & Self ) -> bool {
2020-12-15 22:40:07 +07:00
self . id = = other . id & & self . ordering = = other . ordering
2020-08-17 12:10:51 +02:00
}
}
2020-12-14 00:22:22 +07:00
2020-12-14 17:50:47 +07:00
impl Eq for SignersContainerKey { }
2020-12-14 00:22:22 +07:00
#[ cfg(test) ]
mod signers_container_tests {
use super ::* ;
use crate ::descriptor ;
2021-02-12 22:34:43 -08:00
use crate ::descriptor ::IntoWalletDescriptor ;
2021-02-12 23:02:13 -08:00
use crate ::keys ::{ DescriptorKey , IntoDescriptorKey } ;
2021-02-02 20:06:40 -05:00
use bitcoin ::secp256k1 ::{ All , Secp256k1 } ;
2020-12-14 00:43:07 +07:00
use bitcoin ::util ::bip32 ;
2020-12-14 00:22:22 +07:00
use bitcoin ::util ::psbt ::PartiallySignedTransaction ;
2020-12-14 00:43:07 +07:00
use bitcoin ::Network ;
use miniscript ::ScriptContext ;
use std ::str ::FromStr ;
2020-12-14 00:22:22 +07:00
2021-02-24 13:23:17 +11:00
fn is_equal ( this : & Arc < dyn Signer > , that : & Arc < DummySigner > ) -> bool {
let secp = Secp256k1 ::new ( ) ;
this . id ( & secp ) = = that . id ( & secp )
2020-12-30 14:58:42 +11:00
}
2020-12-14 00:22:22 +07:00
// Signers added with the same ordering (like `Ordering::default`) created from `KeyMap`
// should be preserved and not overwritten.
// This happens usually when a set of signers is created from a descriptor with private keys.
#[ test ]
fn signers_with_same_ordering ( ) {
2021-02-02 20:06:40 -05:00
let secp = Secp256k1 ::new ( ) ;
2020-12-14 00:22:22 +07:00
let ( prvkey1 , _ , _ ) = setup_keys ( TPRV0_STR ) ;
let ( prvkey2 , _ , _ ) = setup_keys ( TPRV1_STR ) ;
2020-12-16 16:10:22 +01:00
let desc = descriptor! ( sh ( multi ( 2 , prvkey1 , prvkey2 ) ) ) . unwrap ( ) ;
2021-02-11 11:00:48 -08:00
let ( _ , keymap ) = desc
. into_wallet_descriptor ( & secp , Network ::Testnet )
. unwrap ( ) ;
2020-12-14 00:22:22 +07:00
let signers = SignersContainer ::from ( keymap ) ;
assert_eq! ( signers . ids ( ) . len ( ) , 2 ) ;
let signers = signers . signers ( ) ;
assert_eq! ( signers . len ( ) , 2 ) ;
}
#[ test ]
fn signers_sorted_by_ordering ( ) {
let mut signers = SignersContainer ::new ( ) ;
2021-02-24 13:23:17 +11:00
let signer1 = Arc ::new ( DummySigner { number : 1 } ) ;
let signer2 = Arc ::new ( DummySigner { number : 2 } ) ;
let signer3 = Arc ::new ( DummySigner { number : 3 } ) ;
2021-02-24 13:39:36 +11:00
// Mixed order insertions verifies we are not inserting at head or tail.
2021-02-24 13:23:17 +11:00
signers . add_external ( SignerId ::Dummy ( 2 ) , SignerOrdering ( 2 ) , signer2 . clone ( ) ) ;
2021-02-24 13:39:36 +11:00
signers . add_external ( SignerId ::Dummy ( 1 ) , SignerOrdering ( 1 ) , signer1 . clone ( ) ) ;
2021-02-24 13:23:17 +11:00
signers . add_external ( SignerId ::Dummy ( 3 ) , SignerOrdering ( 3 ) , signer3 . clone ( ) ) ;
2020-12-14 00:22:22 +07:00
// Check that signers are sorted from lowest to highest ordering
let signers = signers . signers ( ) ;
2020-12-30 14:58:42 +11:00
2021-02-24 13:23:17 +11:00
assert! ( is_equal ( signers [ 0 ] , & signer1 ) ) ;
assert! ( is_equal ( signers [ 1 ] , & signer2 ) ) ;
assert! ( is_equal ( signers [ 2 ] , & signer3 ) ) ;
2020-12-14 00:22:22 +07:00
}
#[ test ]
fn find_signer_by_id ( ) {
let mut signers = SignersContainer ::new ( ) ;
2021-02-24 13:23:17 +11:00
let signer1 = Arc ::new ( DummySigner { number : 1 } ) ;
let signer2 = Arc ::new ( DummySigner { number : 2 } ) ;
let signer3 = Arc ::new ( DummySigner { number : 3 } ) ;
let signer4 = Arc ::new ( DummySigner { number : 3 } ) ; // Same ID as `signer3` but will use lower ordering.
2020-12-14 00:22:22 +07:00
2021-02-24 13:23:17 +11:00
let id1 = SignerId ::Dummy ( 1 ) ;
let id2 = SignerId ::Dummy ( 2 ) ;
let id3 = SignerId ::Dummy ( 3 ) ;
let id_nonexistent = SignerId ::Dummy ( 999 ) ;
2020-12-14 00:22:22 +07:00
signers . add_external ( id1 . clone ( ) , SignerOrdering ( 1 ) , signer1 . clone ( ) ) ;
signers . add_external ( id2 . clone ( ) , SignerOrdering ( 2 ) , signer2 . clone ( ) ) ;
signers . add_external ( id3 . clone ( ) , SignerOrdering ( 3 ) , signer3 . clone ( ) ) ;
2020-12-30 14:58:42 +11:00
assert! ( matches! ( signers . find ( id1 ) , Some ( signer ) if is_equal ( signer , & signer1 ) ) ) ;
assert! ( matches! ( signers . find ( id2 ) , Some ( signer ) if is_equal ( signer , & signer2 ) ) ) ;
assert! ( matches! ( signers . find ( id3 . clone ( ) ) , Some ( signer ) if is_equal ( signer , & signer3 ) ) ) ;
2020-12-14 00:22:22 +07:00
// The `signer4` has the same ID as `signer3` but lower ordering.
// It should be found by `id3` instead of `signer3`.
signers . add_external ( id3 . clone ( ) , SignerOrdering ( 2 ) , signer4 . clone ( ) ) ;
2020-12-30 14:58:42 +11:00
assert! ( matches! ( signers . find ( id3 ) , Some ( signer ) if is_equal ( signer , & signer4 ) ) ) ;
2020-12-14 00:22:22 +07:00
// Can't find anything with ID that doesn't exist
assert! ( matches! ( signers . find ( id_nonexistent ) , None ) ) ;
}
2021-02-24 13:23:17 +11:00
#[ derive(Debug, Clone, Copy) ]
struct DummySigner {
number : u64 ,
}
2020-12-14 00:22:22 +07:00
impl Signer for DummySigner {
2020-12-14 00:43:07 +07:00
fn sign (
& self ,
_psbt : & mut PartiallySignedTransaction ,
_input_index : Option < usize > ,
_secp : & SecpCtx ,
) -> Result < ( ) , SignerError > {
2020-12-14 00:22:22 +07:00
Ok ( ( ) )
}
2021-01-25 15:04:56 -05:00
fn id ( & self , _secp : & SecpCtx ) -> SignerId {
2021-02-24 13:23:17 +11:00
SignerId ::Dummy ( self . number )
2021-01-25 15:04:56 -05:00
}
2020-12-14 00:22:22 +07:00
fn sign_whole_tx ( & self ) -> bool {
true
}
}
const TPRV0_STR :& str = " tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf " ;
const TPRV1_STR :& str = " tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N " ;
const PATH : & str = " m/44'/1'/0'/0 " ;
fn setup_keys < Ctx : ScriptContext > (
tprv : & str ,
) -> ( DescriptorKey < Ctx > , DescriptorKey < Ctx > , Fingerprint ) {
let secp : Secp256k1 < All > = Secp256k1 ::new ( ) ;
let path = bip32 ::DerivationPath ::from_str ( PATH ) . unwrap ( ) ;
let tprv = bip32 ::ExtendedPrivKey ::from_str ( tprv ) . unwrap ( ) ;
let tpub = bip32 ::ExtendedPubKey ::from_private ( & secp , & tprv ) ;
let fingerprint = tprv . fingerprint ( & secp ) ;
2021-02-11 11:00:48 -08:00
let prvkey = ( tprv , path . clone ( ) ) . into_descriptor_key ( ) . unwrap ( ) ;
let pubkey = ( tpub , path ) . into_descriptor_key ( ) . unwrap ( ) ;
2020-12-14 00:22:22 +07:00
( prvkey , pubkey , fingerprint )
}
2020-12-14 00:43:07 +07:00
}