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 {
2022-04-26 16:54:10 +02:00
//! # fn hsm_sign_input(&self, _psbt: &mut psbt::PartiallySignedTransaction, _input: usize) -> Result<(), SignerError> {
2020-09-04 15:45:11 +02:00
//! # 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() }
//! }
//! }
//!
2022-04-26 16:54:10 +02:00
//! impl SignerCommon for CustomSigner {
//! fn id(&self, _secp: &Secp256k1<All>) -> SignerId {
//! self.device.get_id()
//! }
//! }
//!
//! impl InputSigner for CustomSigner {
//! fn sign_input(
2020-09-04 15:45:11 +02:00
//! &self,
//! psbt: &mut psbt::PartiallySignedTransaction,
2022-04-26 16:54:10 +02:00
//! input_index: usize,
2020-11-16 22:07:38 +01:00
//! _secp: &Secp256k1<All>,
2020-09-04 15:45:11 +02:00
//! ) -> Result<(), SignerError> {
2022-04-26 16:54:10 +02:00
//! self.device.hsm_sign_input(psbt, input_index)?;
2020-09-04 15:45:11 +02:00
//!
//! Ok(())
//! }
//! }
//!
//! 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 ;
2022-05-12 17:28:41 +02:00
use std ::ops ::{ Bound ::Included , Deref } ;
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 } ;
2022-05-12 17:28:41 +02:00
use bitcoin ::secp256k1 ::Message ;
2021-03-11 17:39:02 -05:00
use bitcoin ::util ::bip32 ::{ ChildNumber , DerivationPath , ExtendedPrivKey , Fingerprint } ;
2022-04-26 16:54:10 +02:00
use bitcoin ::util ::{ ecdsa , psbt , schnorr , sighash , taproot } ;
use bitcoin ::{ secp256k1 , XOnlyPublicKey } ;
use bitcoin ::{ EcdsaSighashType , PrivateKey , PublicKey , SchnorrSighashType , Script } ;
2020-08-12 12:51:50 +02:00
2022-05-12 17:28:41 +02:00
use miniscript ::descriptor ::{
Descriptor , DescriptorPublicKey , DescriptorSecretKey , DescriptorSinglePriv , DescriptorXKey ,
KeyMap ,
} ;
2022-04-26 16:54:10 +02:00
use miniscript ::{ Legacy , MiniscriptKey , Segwitv0 , Tap } ;
2020-08-12 12:51:50 +02:00
2020-11-16 22:07:38 +01:00
use super ::utils ::SecpCtx ;
2022-05-12 17:28:41 +02:00
use crate ::descriptor ::{ DescriptorMeta , XKeyUtils } ;
2020-08-12 12:51:50 +02:00
/// 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 ,
2022-04-14 17:20:46 +02:00
/// Invalid SIGHASH for the signing context in use
InvalidSighash ,
2022-04-26 15:11:22 +02:00
/// Error while computing the hash to sign
SighashError ( sighash ::Error ) ,
}
impl From < sighash ::Error > for SignerError {
fn from ( e : sighash ::Error ) -> Self {
SignerError ::SighashError ( e )
}
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 { }
2022-05-12 17:28:41 +02:00
/// Signing context
///
/// Used by our software signers to determine the type of signatures to make
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub enum SignerContext {
/// Legacy context
Legacy ,
/// Segwit v0 context (BIP 143)
Segwitv0 ,
/// Taproot context (BIP 340)
Tap {
/// Whether the signer can sign for the internal key or not
is_internal_key : bool ,
} ,
}
/// Wrapper structure to pair a signer with its context
#[ derive(Debug, Clone) ]
pub struct SignerWrapper < S : Sized + fmt ::Debug + Clone > {
signer : S ,
ctx : SignerContext ,
}
impl < S : Sized + fmt ::Debug + Clone > SignerWrapper < S > {
/// Create a wrapped signer from a signer and a context
pub fn new ( signer : S , ctx : SignerContext ) -> Self {
SignerWrapper { signer , ctx }
}
}
impl < S : Sized + fmt ::Debug + Clone > Deref for SignerWrapper < S > {
type Target = S ;
fn deref ( & self ) -> & Self ::Target {
& self . signer
}
}
2022-04-26 16:54:10 +02:00
/// Common signer methods
pub trait SignerCommon : fmt ::Debug + Send + Sync {
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
}
}
2022-04-26 16:54:10 +02:00
/// PSBT Input signer
///
/// This trait can be implemented to provide custom signers to the wallet. If the signer supports signing
/// individual inputs, this trait should be implemented and BDK will provide automatically an implementation
/// for [`TransactionSigner`].
pub trait InputSigner : SignerCommon {
/// Sign a single psbt input
fn sign_input (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
input_index : usize ,
secp : & SecpCtx ,
) -> Result < ( ) , SignerError > ;
}
/// PSBT signer
///
/// This trait can be implemented when the signer can't sign inputs individually, but signs the whole transaction
/// at once.
pub trait TransactionSigner : SignerCommon {
/// Sign all the inputs of the psbt
fn sign_transaction (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
secp : & SecpCtx ,
) -> Result < ( ) , SignerError > ;
}
impl < T : InputSigner > TransactionSigner for T {
fn sign_transaction (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
secp : & SecpCtx ,
) -> Result < ( ) , SignerError > {
for input_index in 0 .. psbt . inputs . len ( ) {
self . sign_input ( psbt , input_index , secp ) ? ;
}
Ok ( ( ) )
}
}
2022-05-12 17:28:41 +02:00
impl SignerCommon for SignerWrapper < DescriptorXKey < ExtendedPrivKey > > {
2022-04-26 16:54:10 +02:00
fn id ( & self , secp : & SecpCtx ) -> SignerId {
SignerId ::from ( self . root_fingerprint ( secp ) )
}
fn descriptor_secret_key ( & self ) -> Option < DescriptorSecretKey > {
2022-05-12 17:28:41 +02:00
Some ( DescriptorSecretKey ::XPrv ( self . signer . clone ( ) ) )
2022-04-26 16:54:10 +02:00
}
}
2022-05-12 17:28:41 +02:00
impl InputSigner for SignerWrapper < DescriptorXKey < ExtendedPrivKey > > {
2022-04-26 16:54:10 +02:00
fn sign_input (
2020-08-12 12:51:50 +02:00
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
2022-04-26 16:54:10 +02:00
input_index : usize ,
2020-11-16 22:07:38 +01:00
secp : & SecpCtx ,
2020-08-12 12:51:50 +02:00
) -> Result < ( ) , SignerError > {
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
} ;
2022-04-14 17:20:46 +02:00
if & secp256k1 ::PublicKey ::from_secret_key ( secp , & derived_key . private_key ) ! = public_key {
2020-09-29 18:18:50 +02:00
Err ( SignerError ::InvalidKey )
} else {
2022-04-14 17:20:46 +02:00
// HD wallets imply compressed keys
2022-05-12 17:28:41 +02:00
let priv_key = PrivateKey {
2022-04-14 17:20:46 +02:00
compressed : true ,
network : self . xkey . network ,
inner : derived_key . private_key ,
2022-05-12 17:28:41 +02:00
} ;
SignerWrapper ::new ( priv_key , self . ctx ) . sign_input ( psbt , input_index , secp )
2020-09-29 18:18:50 +02:00
}
2020-08-12 12:51:50 +02:00
}
2022-04-26 16:54:10 +02:00
}
2020-08-12 12:51:50 +02:00
2022-05-12 17:28:41 +02:00
impl SignerCommon for SignerWrapper < PrivateKey > {
2021-01-25 15:04:56 -05:00
fn id ( & self , secp : & SecpCtx ) -> SignerId {
2022-04-26 16:54:10 +02:00
SignerId ::from ( self . public_key ( secp ) . to_pubkeyhash ( ) )
2021-01-25 15:04:56 -05:00
}
2020-08-12 12:51:50 +02:00
fn descriptor_secret_key ( & self ) -> Option < DescriptorSecretKey > {
2022-04-26 16:54:10 +02:00
Some ( DescriptorSecretKey ::SinglePriv ( DescriptorSinglePriv {
2022-05-12 17:28:41 +02:00
key : self . signer ,
2022-04-26 16:54:10 +02:00
origin : None ,
} ) )
2020-08-12 12:51:50 +02:00
}
}
2022-05-12 17:28:41 +02:00
impl InputSigner for SignerWrapper < PrivateKey > {
2022-04-26 16:54:10 +02:00
fn sign_input (
2020-08-12 12:51:50 +02:00
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
2022-04-26 16:54:10 +02:00
input_index : usize ,
2020-11-16 22:07:38 +01:00
secp : & SecpCtx ,
2020-08-12 12:51:50 +02:00
) -> Result < ( ) , SignerError > {
2022-04-14 17:20:46 +02:00
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . 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 ( ( ) ) ;
}
2022-04-26 15:11:22 +02:00
let pubkey = PublicKey ::from_private_key ( secp , self ) ;
2022-04-26 16:54:10 +02:00
let x_only_pubkey = XOnlyPublicKey ::from ( pubkey . inner ) ;
2022-05-12 17:28:41 +02:00
if let SignerContext ::Tap { is_internal_key } = self . ctx {
if is_internal_key & & psbt . inputs [ input_index ] . tap_key_sig . is_none ( ) {
2022-04-26 16:54:10 +02:00
let ( hash , hash_ty ) = Tap ::sighash ( psbt , input_index , None ) ? ;
sign_psbt_schnorr (
& self . inner ,
x_only_pubkey ,
None ,
& mut psbt . inputs [ input_index ] ,
hash ,
hash_ty ,
secp ,
) ;
}
2020-08-12 12:51:50 +02:00
2022-05-12 17:28:41 +02:00
if let Some ( ( leaf_hashes , _ ) ) =
psbt . inputs [ input_index ] . tap_key_origins . get ( & x_only_pubkey )
{
let leaf_hashes = leaf_hashes
. iter ( )
. filter ( | lh | {
! psbt . inputs [ input_index ]
. tap_script_sigs
. contains_key ( & ( x_only_pubkey , * * lh ) )
} )
. cloned ( )
. collect ::< Vec < _ > > ( ) ;
for lh in leaf_hashes {
let ( hash , hash_ty ) = Tap ::sighash ( psbt , input_index , Some ( lh ) ) ? ;
sign_psbt_schnorr (
& self . inner ,
x_only_pubkey ,
Some ( lh ) ,
& mut psbt . inputs [ input_index ] ,
hash ,
hash_ty ,
secp ,
) ;
}
2022-04-26 16:54:10 +02:00
}
2020-08-12 12:51:50 +02:00
2022-05-12 17:28:41 +02:00
return Ok ( ( ) ) ;
}
if psbt . inputs [ input_index ] . partial_sigs . contains_key ( & pubkey ) {
return Ok ( ( ) ) ;
2022-04-26 16:54:10 +02:00
}
2020-08-12 12:51:50 +02:00
2022-05-12 17:28:41 +02:00
let ( hash , hash_ty ) = match self . ctx {
SignerContext ::Segwitv0 = > Segwitv0 ::sighash ( psbt , input_index , ( ) ) ? ,
SignerContext ::Legacy = > Legacy ::sighash ( psbt , input_index , ( ) ) ? ,
_ = > return Ok ( ( ) ) , // handled above
} ;
sign_psbt_ecdsa (
& self . inner ,
pubkey ,
& mut psbt . inputs [ input_index ] ,
hash ,
hash_ty ,
secp ,
) ;
2020-08-12 12:51:50 +02:00
Ok ( ( ) )
}
2022-04-26 16:54:10 +02:00
}
2020-08-12 12:51:50 +02:00
2022-04-26 16:54:10 +02:00
fn sign_psbt_ecdsa (
secret_key : & secp256k1 ::SecretKey ,
pubkey : PublicKey ,
psbt_input : & mut psbt ::Input ,
hash : bitcoin ::Sighash ,
hash_ty : EcdsaSighashType ,
secp : & SecpCtx ,
) {
let sig = secp . sign_ecdsa (
& Message ::from_slice ( & hash . into_inner ( ) [ .. ] ) . unwrap ( ) ,
secret_key ,
) ;
let final_signature = ecdsa ::EcdsaSig { sig , hash_ty } ;
psbt_input . partial_sigs . insert ( pubkey , final_signature ) ;
}
2021-01-25 15:04:56 -05:00
2022-04-26 16:54:10 +02:00
// Calling this with `leaf_hash` = `None` will sign for key-spend
fn sign_psbt_schnorr (
secret_key : & secp256k1 ::SecretKey ,
pubkey : XOnlyPublicKey ,
leaf_hash : Option < taproot ::TapLeafHash > ,
psbt_input : & mut psbt ::Input ,
hash : taproot ::TapSighashHash ,
hash_ty : SchnorrSighashType ,
secp : & SecpCtx ,
) {
use schnorr ::TapTweak ;
let keypair = secp256k1 ::KeyPair ::from_seckey_slice ( secp , secret_key . as_ref ( ) ) . unwrap ( ) ;
let keypair = match leaf_hash {
None = > keypair
. tap_tweak ( secp , psbt_input . tap_merkle_root )
. into_inner ( ) ,
Some ( _ ) = > keypair , // no tweak for script spend
} ;
let sig = secp . sign_schnorr (
& Message ::from_slice ( & hash . into_inner ( ) [ .. ] ) . unwrap ( ) ,
& keypair ,
) ;
let final_signature = schnorr ::SchnorrSig { sig , hash_ty } ;
if let Some ( lh ) = leaf_hash {
psbt_input
. tap_script_sigs
. insert ( ( pubkey , lh ) , final_signature ) ;
} else {
psbt_input . tap_key_sig = Some ( final_signature )
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) ]
2022-04-26 16:54:10 +02:00
pub struct SignersContainer ( BTreeMap < SignersContainerKey , Arc < dyn TransactionSigner > > ) ;
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 ( )
}
2022-05-12 17:28:41 +02:00
/// Build a new signer container from a [`KeyMap`]
///
/// Also looks at the corresponding descriptor to determine the [`SignerContext`] to attach to
/// the signers
pub fn build (
keymap : KeyMap ,
descriptor : & Descriptor < DescriptorPublicKey > ,
secp : & SecpCtx ,
) -> SignersContainer {
2020-08-12 12:51:50 +02:00
let mut container = SignersContainer ::new ( ) ;
2022-05-12 17:28:41 +02:00
for ( pubkey , secret ) in keymap {
let ctx = match descriptor {
Descriptor ::Tr ( tr ) = > SignerContext ::Tap {
is_internal_key : tr . internal_key ( ) = = & pubkey ,
} ,
_ if descriptor . is_witness ( ) = > SignerContext ::Segwitv0 ,
_ = > SignerContext ::Legacy ,
} ;
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 (
2022-05-12 17:28:41 +02:00
SignerId ::from ( private_key . key . public_key ( secp ) . to_pubkeyhash ( ) ) ,
2020-08-17 12:10:51 +02:00
SignerOrdering ::default ( ) ,
2022-05-12 17:28:41 +02:00
Arc ::new ( SignerWrapper ::new ( private_key . key , ctx ) ) ,
2020-08-15 23:21:13 +02:00
) ,
DescriptorSecretKey ::XPrv ( xprv ) = > container . add_external (
2022-05-12 17:28:41 +02:00
SignerId ::from ( xprv . root_fingerprint ( secp ) ) ,
2020-08-17 12:10:51 +02:00
SignerOrdering ::default ( ) ,
2022-05-12 17:28:41 +02:00
Arc ::new ( SignerWrapper ::new ( xprv , ctx ) ) ,
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 ,
2022-04-26 16:54:10 +02:00
signer : Arc < dyn TransactionSigner > ,
) -> Option < Arc < dyn TransactionSigner > > {
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
2022-04-26 16:54:10 +02:00
pub fn remove (
& mut self ,
id : SignerId ,
ordering : SignerOrdering ,
) -> Option < Arc < dyn TransactionSigner > > {
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`
2022-04-26 16:54:10 +02:00
pub fn signers ( & self ) -> Vec < & Arc < dyn TransactionSigner > > {
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.
2022-04-26 16:54:10 +02:00
pub fn find ( & self , id : SignerId ) -> Option < & Arc < dyn TransactionSigner > > {
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
}
2022-05-03 12:41:22 +02:00
#[ allow(clippy::derivable_impls) ]
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 {
2022-04-26 16:54:10 +02:00
type Extra ;
type Sighash ;
type SighashType ;
2020-08-12 12:51:50 +02:00
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
2022-04-26 16:54:10 +02:00
extra : Self ::Extra ,
) -> Result < ( Self ::Sighash , Self ::SighashType ) , SignerError > ;
2020-08-12 12:51:50 +02:00
}
impl ComputeSighash for Legacy {
2022-04-26 16:54:10 +02:00
type Extra = ( ) ;
type Sighash = bitcoin ::Sighash ;
type SighashType = EcdsaSighashType ;
2020-08-12 12:51:50 +02:00
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
2022-04-26 16:54:10 +02:00
_extra : ( ) ,
) -> Result < ( Self ::Sighash , Self ::SighashType ) , SignerError > {
2022-04-14 17:20:46 +02:00
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . unsigned_tx . input . len ( ) {
2020-08-12 12:51:50 +02:00
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
let psbt_input = & psbt . inputs [ input_index ] ;
2022-04-14 17:20:46 +02:00
let tx_input = & psbt . unsigned_tx . input [ input_index ] ;
2020-08-12 12:51:50 +02:00
2022-04-26 15:11:22 +02:00
let sighash = psbt_input
. sighash_type
2022-04-26 16:54:10 +02:00
. unwrap_or_else ( | | EcdsaSighashType ::All . into ( ) )
. ecdsa_hash_ty ( )
. map_err ( | _ | SignerError ::InvalidSighash ) ? ;
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 ( (
2022-04-26 15:11:22 +02:00
sighash ::SighashCache ::new ( & psbt . unsigned_tx ) . legacy_signature_hash (
input_index ,
& script ,
sighash . to_u32 ( ) ,
) ? ,
2020-08-12 12:51:50 +02:00
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 {
2022-04-26 16:54:10 +02:00
type Extra = ( ) ;
type Sighash = bitcoin ::Sighash ;
type SighashType = EcdsaSighashType ;
2020-08-12 12:51:50 +02:00
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
2022-04-26 16:54:10 +02:00
_extra : ( ) ,
) -> Result < ( Self ::Sighash , Self ::SighashType ) , SignerError > {
2022-04-14 17:20:46 +02:00
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . unsigned_tx . input . len ( ) {
2020-08-12 12:51:50 +02:00
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
let psbt_input = & psbt . inputs [ input_index ] ;
2022-04-14 17:20:46 +02:00
let tx_input = & psbt . unsigned_tx . input [ input_index ] ;
2020-08-12 12:51:50 +02:00
2022-04-14 17:20:46 +02:00
let sighash = psbt_input
. sighash_type
2022-04-26 15:11:22 +02:00
. unwrap_or_else ( | | EcdsaSighashType ::All . into ( ) )
2022-04-14 17:20:46 +02:00
. ecdsa_hash_ty ( )
. map_err ( | _ | SignerError ::InvalidSighash ) ? ;
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 ( (
2022-04-26 15:11:22 +02:00
sighash ::SighashCache ::new ( & psbt . unsigned_tx ) . segwit_signature_hash (
2020-08-12 12:51:50 +02:00
input_index ,
& script ,
value ,
sighash ,
2022-04-26 15:11:22 +02:00
) ? ,
2022-04-26 16:54:10 +02:00
sighash ,
) )
}
}
impl ComputeSighash for Tap {
type Extra = Option < taproot ::TapLeafHash > ;
type Sighash = taproot ::TapSighashHash ;
type SighashType = SchnorrSighashType ;
fn sighash (
psbt : & psbt ::PartiallySignedTransaction ,
input_index : usize ,
extra : Self ::Extra ,
) -> Result < ( Self ::Sighash , SchnorrSighashType ) , SignerError > {
if input_index > = psbt . inputs . len ( ) | | input_index > = psbt . unsigned_tx . input . len ( ) {
return Err ( SignerError ::InputIndexOutOfRange ) ;
}
let psbt_input = & psbt . inputs [ input_index ] ;
let sighash_type = psbt_input
. sighash_type
. unwrap_or_else ( | | SchnorrSighashType ::Default . into ( ) )
. schnorr_hash_ty ( )
. map_err ( | _ | SignerError ::InvalidSighash ) ? ;
let witness_utxos = psbt
. inputs
. iter ( )
. cloned ( )
. map ( | i | i . witness_utxo )
. collect ::< Vec < _ > > ( ) ;
let mut all_witness_utxos = vec! [ ] ;
let mut cache = sighash ::SighashCache ::new ( & psbt . unsigned_tx ) ;
let is_anyone_can_pay = psbt ::PsbtSighashType ::from ( sighash_type ) . to_u32 ( ) & 0x80 ! = 0 ;
let prevouts = if is_anyone_can_pay {
sighash ::Prevouts ::One (
input_index ,
witness_utxos [ input_index ]
. as_ref ( )
. ok_or ( SignerError ::MissingWitnessUtxo ) ? ,
)
} else if witness_utxos . iter ( ) . all ( Option ::is_some ) {
all_witness_utxos . extend ( witness_utxos . iter ( ) . filter_map ( | x | x . as_ref ( ) ) ) ;
sighash ::Prevouts ::All ( & all_witness_utxos )
} else {
return Err ( SignerError ::MissingWitnessUtxo ) ;
} ;
// Assume no OP_CODESEPARATOR
let extra = extra . map ( | leaf_hash | ( leaf_hash , 0xFFFFFFFF ) ) ;
Ok ( (
cache . taproot_signature_hash ( input_index , & prevouts , None , extra , sighash_type ) ? ,
sighash_type ,
2020-08-12 12:51:50 +02:00
) )
}
}
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 ;
use bitcoin ::Network ;
use miniscript ::ScriptContext ;
use std ::str ::FromStr ;
2020-12-14 00:22:22 +07:00
2022-04-26 16:54:10 +02:00
fn is_equal ( this : & Arc < dyn TransactionSigner > , that : & Arc < DummySigner > ) -> bool {
2021-02-24 13:23:17 +11:00
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 ( ) ;
2022-05-12 17:28:41 +02:00
let ( wallet_desc , keymap ) = desc
2021-02-11 11:00:48 -08:00
. into_wallet_descriptor ( & secp , Network ::Testnet )
. unwrap ( ) ;
2020-12-14 00:22:22 +07:00
2022-05-12 17:28:41 +02:00
let signers = SignersContainer ::build ( keymap , & wallet_desc , & secp ) ;
2020-12-14 00:22:22 +07:00
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 ,
}
2022-04-26 16:54:10 +02:00
impl SignerCommon for DummySigner {
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
}
2022-04-26 16:54:10 +02:00
}
2020-12-14 00:22:22 +07:00
2022-04-26 16:54:10 +02:00
impl TransactionSigner for DummySigner {
fn sign_transaction (
& self ,
_psbt : & mut psbt ::PartiallySignedTransaction ,
_secp : & SecpCtx ,
) -> Result < ( ) , SignerError > {
Ok ( ( ) )
2020-12-14 00:22:22 +07:00
}
}
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 ( ) ;
2022-04-14 17:20:46 +02:00
let tpub = bip32 ::ExtendedPubKey ::from_priv ( & secp , & tprv ) ;
2020-12-14 00:22:22 +07:00
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
}