• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bitcoindevkit / bdk / 9475497656

12 Jun 2024 02:00AM UTC coverage: 82.974% (-0.4%) from 83.405%
9475497656

Pull #1468

github

web-flow
Merge 44e446faa into 473ef9714
Pull Request #1468: wip(feat): use `Weight` type instead of `usize`

112 of 190 new or added lines in 19 files covered. (58.95%)

13 existing lines in 3 files now uncovered.

11253 of 13562 relevant lines covered (82.97%)

16764.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.46
/crates/wallet/src/wallet/signer.rs
1
// Bitcoin Dev Kit
2
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3
//
4
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5
//
6
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9
// You may not use this file except in accordance with one or both of these
10
// licenses.
11

12
//! Generalized signers
13
//!
14
//! This module provides the ability to add customized signers to a [`Wallet`](super::Wallet)
15
//! through the [`Wallet::add_signer`](super::Wallet::add_signer) function.
16
//!
17
//! ```
18
//! # use alloc::sync::Arc;
19
//! # use core::str::FromStr;
20
//! # use bitcoin::secp256k1::{Secp256k1, All};
21
//! # use bitcoin::*;
22
//! # use bdk_wallet::signer::*;
23
//! # use bdk_wallet::*;
24
//! # #[derive(Debug)]
25
//! # struct CustomHSM;
26
//! # impl CustomHSM {
27
//! #     fn hsm_sign_input(&self, _psbt: &mut Psbt, _input: usize) -> Result<(), SignerError> {
28
//! #         Ok(())
29
//! #     }
30
//! #     fn connect() -> Self {
31
//! #         CustomHSM
32
//! #     }
33
//! #     fn get_id(&self) -> SignerId {
34
//! #         SignerId::Dummy(0)
35
//! #     }
36
//! # }
37
//! #[derive(Debug)]
38
//! struct CustomSigner {
39
//!     device: CustomHSM,
40
//! }
41
//!
42
//! impl CustomSigner {
43
//!     fn connect() -> Self {
44
//!         CustomSigner { device: CustomHSM::connect() }
45
//!     }
46
//! }
47
//!
48
//! impl SignerCommon for CustomSigner {
49
//!     fn id(&self, _secp: &Secp256k1<All>) -> SignerId {
50
//!         self.device.get_id()
51
//!     }
52
//! }
53
//!
54
//! impl InputSigner for CustomSigner {
55
//!     fn sign_input(
56
//!         &self,
57
//!         psbt: &mut Psbt,
58
//!         input_index: usize,
59
//!         _sign_options: &SignOptions,
60
//!         _secp: &Secp256k1<All>,
61
//!     ) -> Result<(), SignerError> {
62
//!         self.device.hsm_sign_input(psbt, input_index)?;
63
//!
64
//!         Ok(())
65
//!     }
66
//! }
67
//!
68
//! let custom_signer = CustomSigner::connect();
69
//!
70
//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/0/*)";
71
//! let change_descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/1/*)";
72
//! let mut wallet = Wallet::new_no_persist(descriptor, change_descriptor, Network::Testnet)?;
73
//! wallet.add_signer(
74
//!     KeychainKind::External,
75
//!     SignerOrdering(200),
76
//!     Arc::new(custom_signer)
77
//! );
78
//!
79
//! # Ok::<_, anyhow::Error>(())
80
//! ```
81

82
use crate::collections::BTreeMap;
83
use alloc::string::String;
84
use alloc::sync::Arc;
85
use alloc::vec::Vec;
86
use core::cmp::Ordering;
87
use core::fmt;
88
use core::ops::{Bound::Included, Deref};
89

90
use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv};
91
use bitcoin::hashes::hash160;
92
use bitcoin::secp256k1::Message;
93
use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType};
94
use bitcoin::{ecdsa, psbt, sighash, taproot, transaction};
95
use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1};
96
use bitcoin::{PrivateKey, Psbt, PublicKey};
97

98
use miniscript::descriptor::{
99
    Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey,
100
    InnerXKey, KeyMap, SinglePriv, SinglePubKey,
101
};
102
use miniscript::{Legacy, Segwitv0, SigType, Tap, ToPublicKey};
103

104
use super::utils::SecpCtx;
105
use crate::descriptor::{DescriptorMeta, XKeyUtils};
106
use crate::psbt::PsbtUtils;
107
use crate::wallet::error::MiniscriptPsbtError;
108

109
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
110
/// multiple of them
111
#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Hash)]
112
pub enum SignerId {
113
    /// Bitcoin HASH160 (RIPEMD160 after SHA256) hash of an ECDSA public key
114
    PkHash(hash160::Hash),
115
    /// The fingerprint of a BIP32 extended key
116
    Fingerprint(Fingerprint),
117
    /// Dummy identifier
118
    Dummy(u64),
119
}
120

121
impl From<hash160::Hash> for SignerId {
122
    fn from(hash: hash160::Hash) -> SignerId {
2,472✔
123
        SignerId::PkHash(hash)
2,472✔
124
    }
2,472✔
125
}
126

127
impl From<Fingerprint> for SignerId {
128
    fn from(fing: Fingerprint) -> SignerId {
3,006✔
129
        SignerId::Fingerprint(fing)
3,006✔
130
    }
3,006✔
131
}
132

133
/// Signing error
134
#[derive(Debug)]
135
pub enum SignerError {
136
    /// The private key is missing for the required public key
137
    MissingKey,
138
    /// The private key in use has the right fingerprint but derives differently than expected
139
    InvalidKey,
140
    /// The user canceled the operation
141
    UserCanceled,
142
    /// Input index is out of range
143
    InputIndexOutOfRange,
144
    /// The `non_witness_utxo` field of the transaction is required to sign this input
145
    MissingNonWitnessUtxo,
146
    /// The `non_witness_utxo` specified is invalid
147
    InvalidNonWitnessUtxo,
148
    /// The `witness_utxo` field of the transaction is required to sign this input
149
    MissingWitnessUtxo,
150
    /// The `witness_script` field of the transaction is required to sign this input
151
    MissingWitnessScript,
152
    /// The fingerprint and derivation path are missing from the psbt input
153
    MissingHdKeypath,
154
    /// The psbt contains a non-`SIGHASH_ALL` sighash in one of its input and the user hasn't
155
    /// explicitly allowed them
156
    ///
157
    /// To enable signing transactions with non-standard sighashes set
158
    /// [`SignOptions::allow_all_sighashes`] to `true`.
159
    NonStandardSighash,
160
    /// Invalid SIGHASH for the signing context in use
161
    InvalidSighash,
162
    /// Error while computing the hash to sign a P2WPKH input.
163
    SighashP2wpkh(sighash::P2wpkhError),
164
    /// Error while computing the hash to sign a Taproot input.
165
    SighashTaproot(sighash::TaprootError),
166
    /// Error while computing the hash, out of bounds access on the transaction inputs.
167
    TxInputsIndexError(transaction::InputsIndexError),
168
    /// Error while computing the hash, out of bounds access on the transaction outputs.
169
    TxOutputsIndexError(transaction::OutputsIndexError),
170
    /// Miniscript PSBT error
171
    MiniscriptPsbt(MiniscriptPsbtError),
172
    /// To be used only by external libraries implementing [`InputSigner`] or
173
    /// [`TransactionSigner`], so that they can return their own custom errors, without having to
174
    /// modify [`SignerError`] in BDK.
175
    External(String),
176
}
177

178
impl From<transaction::InputsIndexError> for SignerError {
NEW
179
    fn from(v: transaction::InputsIndexError) -> Self {
×
NEW
180
        Self::TxInputsIndexError(v)
×
NEW
181
    }
×
182
}
183

184
impl From<transaction::OutputsIndexError> for SignerError {
NEW
185
    fn from(v: transaction::OutputsIndexError) -> Self {
×
NEW
186
        Self::TxOutputsIndexError(v)
×
NEW
187
    }
×
188
}
189

190
impl From<sighash::P2wpkhError> for SignerError {
NEW
191
    fn from(e: sighash::P2wpkhError) -> Self {
×
NEW
192
        Self::SighashP2wpkh(e)
×
NEW
193
    }
×
194
}
195

196
impl From<sighash::TaprootError> for SignerError {
NEW
197
    fn from(e: sighash::TaprootError) -> Self {
×
NEW
198
        Self::SighashTaproot(e)
×
UNCOV
199
    }
×
200
}
201

202
impl fmt::Display for SignerError {
203
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
204
        match self {
×
205
            Self::MissingKey => write!(f, "Missing private key"),
×
206
            Self::InvalidKey => write!(f, "The private key in use has the right fingerprint but derives differently than expected"),
×
207
            Self::UserCanceled => write!(f, "The user canceled the operation"),
×
208
            Self::InputIndexOutOfRange => write!(f, "Input index out of range"),
×
209
            Self::MissingNonWitnessUtxo => write!(f, "Missing non-witness UTXO"),
×
210
            Self::InvalidNonWitnessUtxo => write!(f, "Invalid non-witness UTXO"),
×
211
            Self::MissingWitnessUtxo => write!(f, "Missing witness UTXO"),
×
212
            Self::MissingWitnessScript => write!(f, "Missing witness script"),
×
213
            Self::MissingHdKeypath => write!(f, "Missing fingerprint and derivation path"),
×
214
            Self::NonStandardSighash => write!(f, "The psbt contains a non standard sighash"),
×
215
            Self::InvalidSighash => write!(f, "Invalid SIGHASH for the signing context in use"),
×
NEW
216
            Self::SighashP2wpkh(err) => write!(f, "Error while computing the hash to sign a P2WPKH input: {}", err),
×
NEW
217
            Self::SighashTaproot(err) => write!(f, "Error while computing the hash to sign a Taproot input: {}", err),
×
NEW
218
            Self::TxInputsIndexError(err) => write!(f, "Error while computing the hash, out of bounds access on the transaction inputs: {}", err),
×
NEW
219
            Self::TxOutputsIndexError(err) => write!(f, "Error while computing the hash, out of bounds access on the transaction outputs: {}", err),
×
220
            Self::MiniscriptPsbt(err) => write!(f, "Miniscript PSBT error: {}", err),
×
221
            Self::External(err) => write!(f, "{}", err),
×
222
        }
223
    }
×
224
}
225

226
#[cfg(feature = "std")]
227
impl std::error::Error for SignerError {}
228

229
/// Signing context
230
///
231
/// Used by our software signers to determine the type of signatures to make
232
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233
pub enum SignerContext {
234
    /// Legacy context
235
    Legacy,
236
    /// Segwit v0 context (BIP 143)
237
    Segwitv0,
238
    /// Taproot context (BIP 340)
239
    Tap {
240
        /// Whether the signer can sign for the internal key or not
241
        is_internal_key: bool,
242
    },
243
}
244

245
/// Wrapper to pair a signer with its context
246
#[derive(Debug, Clone)]
247
pub struct SignerWrapper<S: Sized + fmt::Debug + Clone> {
248
    signer: S,
249
    ctx: SignerContext,
250
}
251

252
impl<S: Sized + fmt::Debug + Clone> SignerWrapper<S> {
253
    /// Create a wrapped signer from a signer and a context
254
    pub fn new(signer: S, ctx: SignerContext) -> Self {
2,826✔
255
        SignerWrapper { signer, ctx }
2,826✔
256
    }
2,826✔
257
}
258

259
impl<S: Sized + fmt::Debug + Clone> Deref for SignerWrapper<S> {
260
    type Target = S;
261

262
    fn deref(&self) -> &Self::Target {
1,784✔
263
        &self.signer
1,784✔
264
    }
1,784✔
265
}
266

267
/// Common signer methods
268
pub trait SignerCommon: fmt::Debug + Send + Sync {
269
    /// Return the [`SignerId`] for this signer
270
    ///
271
    /// The [`SignerId`] can be used to lookup a signer in the [`Wallet`](crate::Wallet)'s signers map or to
272
    /// compare two signers.
273
    fn id(&self, secp: &SecpCtx) -> SignerId;
274

275
    /// Return the secret key for the signer
276
    ///
277
    /// This is used internally to reconstruct the original descriptor that may contain secrets.
278
    /// External signers that are meant to keep key isolated should just return `None` here (which
279
    /// is the default for this method, if not overridden).
280
    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
×
281
        None
×
282
    }
×
283
}
284

285
/// PSBT Input signer
286
///
287
/// This trait can be implemented to provide custom signers to the wallet. If the signer supports signing
288
/// individual inputs, this trait should be implemented and BDK will provide automatically an implementation
289
/// for [`TransactionSigner`].
290
pub trait InputSigner: SignerCommon {
291
    /// Sign a single psbt input
292
    fn sign_input(
293
        &self,
294
        psbt: &mut Psbt,
295
        input_index: usize,
296
        sign_options: &SignOptions,
297
        secp: &SecpCtx,
298
    ) -> Result<(), SignerError>;
299
}
300

301
/// PSBT signer
302
///
303
/// This trait can be implemented when the signer can't sign inputs individually, but signs the whole transaction
304
/// at once.
305
pub trait TransactionSigner: SignerCommon {
306
    /// Sign all the inputs of the psbt
307
    fn sign_transaction(
308
        &self,
309
        psbt: &mut Psbt,
310
        sign_options: &SignOptions,
311
        secp: &SecpCtx,
312
    ) -> Result<(), SignerError>;
313
}
314

315
impl<T: InputSigner> TransactionSigner for T {
316
    fn sign_transaction(
664✔
317
        &self,
664✔
318
        psbt: &mut Psbt,
664✔
319
        sign_options: &SignOptions,
664✔
320
        secp: &SecpCtx,
664✔
321
    ) -> Result<(), SignerError> {
664✔
322
        for input_index in 0..psbt.inputs.len() {
744✔
323
            self.sign_input(psbt, input_index, sign_options, secp)?;
744✔
324
        }
325

326
        Ok(())
632✔
327
    }
664✔
328
}
329

330
impl SignerCommon for SignerWrapper<DescriptorXKey<Xpriv>> {
331
    fn id(&self, secp: &SecpCtx) -> SignerId {
16✔
332
        SignerId::from(self.root_fingerprint(secp))
16✔
333
    }
16✔
334

335
    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
18✔
336
        Some(DescriptorSecretKey::XPrv(self.signer.clone()))
18✔
337
    }
18✔
338
}
339

340
impl InputSigner for SignerWrapper<DescriptorXKey<Xpriv>> {
341
    fn sign_input(
448✔
342
        &self,
448✔
343
        psbt: &mut Psbt,
448✔
344
        input_index: usize,
448✔
345
        sign_options: &SignOptions,
448✔
346
        secp: &SecpCtx,
448✔
347
    ) -> Result<(), SignerError> {
448✔
348
        if input_index >= psbt.inputs.len() {
448✔
349
            return Err(SignerError::InputIndexOutOfRange);
×
350
        }
448✔
351

448✔
352
        if psbt.inputs[input_index].final_script_sig.is_some()
448✔
353
            || psbt.inputs[input_index].final_script_witness.is_some()
432✔
354
        {
355
            return Ok(());
16✔
356
        }
432✔
357

432✔
358
        let tap_key_origins = psbt.inputs[input_index]
432✔
359
            .tap_key_origins
432✔
360
            .iter()
432✔
361
            .map(|(pk, (_, keysource))| (SinglePubKey::XOnly(*pk), keysource));
432✔
362
        let (public_key, full_path) = match psbt.inputs[input_index]
432✔
363
            .bip32_derivation
432✔
364
            .iter()
432✔
365
            .map(|(pk, keysource)| (SinglePubKey::FullKey(PublicKey::new(*pk)), keysource))
432✔
366
            .chain(tap_key_origins)
432✔
367
            .find_map(|(pk, keysource)| {
560✔
368
                if self.matches(keysource, secp).is_some() {
560✔
369
                    Some((pk, keysource.1.clone()))
144✔
370
                } else {
371
                    None
416✔
372
                }
373
            }) {
560✔
374
            Some((pk, full_path)) => (pk, full_path),
144✔
375
            None => return Ok(()),
288✔
376
        };
377

378
        let derived_key = match self.origin.clone() {
144✔
379
            Some((_fingerprint, origin_path)) => {
16✔
380
                let deriv_path = DerivationPath::from(
16✔
381
                    &full_path.into_iter().cloned().collect::<Vec<ChildNumber>>()
16✔
382
                        [origin_path.len()..],
16✔
383
                );
16✔
384
                self.xkey.derive_priv(secp, &deriv_path).unwrap()
16✔
385
            }
386
            None => self.xkey.derive_priv(secp, &full_path).unwrap(),
128✔
387
        };
388

389
        let computed_pk = secp256k1::PublicKey::from_secret_key(secp, &derived_key.private_key);
144✔
390
        let valid_key = match public_key {
144✔
391
            SinglePubKey::FullKey(pk) if pk.inner == computed_pk => true,
120✔
392
            SinglePubKey::XOnly(x_only) if XOnlyPublicKey::from(computed_pk) == x_only => true,
24✔
393
            _ => false,
×
394
        };
395
        if !valid_key {
144✔
396
            Err(SignerError::InvalidKey)
×
397
        } else {
398
            // HD wallets imply compressed keys
399
            let priv_key = PrivateKey {
144✔
400
                compressed: true,
144✔
401
                network: self.xkey.network,
144✔
402
                inner: derived_key.private_key,
144✔
403
            };
144✔
404

144✔
405
            SignerWrapper::new(priv_key, self.ctx).sign_input(psbt, input_index, sign_options, secp)
144✔
406
        }
407
    }
448✔
408
}
409

410
fn multikey_to_xkeys<K: InnerXKey + Clone>(
×
411
    multikey: DescriptorMultiXKey<K>,
×
412
) -> Vec<DescriptorXKey<K>> {
×
413
    multikey
×
414
        .derivation_paths
×
415
        .into_paths()
×
416
        .into_iter()
×
417
        .map(|derivation_path| DescriptorXKey {
×
418
            origin: multikey.origin.clone(),
×
419
            xkey: multikey.xkey.clone(),
×
420
            derivation_path,
×
421
            wildcard: multikey.wildcard,
×
422
        })
×
423
        .collect()
×
424
}
×
425

426
impl SignerCommon for SignerWrapper<DescriptorMultiXKey<Xpriv>> {
427
    fn id(&self, secp: &SecpCtx) -> SignerId {
×
428
        SignerId::from(self.root_fingerprint(secp))
×
429
    }
×
430

431
    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
×
432
        Some(DescriptorSecretKey::MultiXPrv(self.signer.clone()))
×
433
    }
×
434
}
435

436
impl InputSigner for SignerWrapper<DescriptorMultiXKey<Xpriv>> {
437
    fn sign_input(
×
438
        &self,
×
439
        psbt: &mut Psbt,
×
440
        input_index: usize,
×
441
        sign_options: &SignOptions,
×
442
        secp: &SecpCtx,
×
443
    ) -> Result<(), SignerError> {
×
444
        let xkeys = multikey_to_xkeys(self.signer.clone());
×
445
        for xkey in xkeys {
×
446
            SignerWrapper::new(xkey, self.ctx).sign_input(psbt, input_index, sign_options, secp)?
×
447
        }
448
        Ok(())
×
449
    }
×
450
}
451

452
impl SignerCommon for SignerWrapper<PrivateKey> {
453
    fn id(&self, secp: &SecpCtx) -> SignerId {
40✔
454
        SignerId::from(self.public_key(secp).to_pubkeyhash(SigType::Ecdsa))
40✔
455
    }
40✔
456

457
    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
×
458
        Some(DescriptorSecretKey::Single(SinglePriv {
×
459
            key: self.signer,
×
460
            origin: None,
×
461
        }))
×
462
    }
×
463
}
464

465
impl InputSigner for SignerWrapper<PrivateKey> {
466
    fn sign_input(
440✔
467
        &self,
440✔
468
        psbt: &mut Psbt,
440✔
469
        input_index: usize,
440✔
470
        sign_options: &SignOptions,
440✔
471
        secp: &SecpCtx,
440✔
472
    ) -> Result<(), SignerError> {
440✔
473
        if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
440✔
474
            return Err(SignerError::InputIndexOutOfRange);
16✔
475
        }
424✔
476

424✔
477
        if psbt.inputs[input_index].final_script_sig.is_some()
424✔
478
            || psbt.inputs[input_index].final_script_witness.is_some()
408✔
479
        {
480
            return Ok(());
16✔
481
        }
408✔
482

408✔
483
        let pubkey = PublicKey::from_private_key(secp, self);
408✔
484
        let x_only_pubkey = XOnlyPublicKey::from(pubkey.inner);
408✔
485

486
        if let SignerContext::Tap { is_internal_key } = self.ctx {
408✔
487
            if let Some(psbt_internal_key) = psbt.inputs[input_index].tap_internal_key {
208✔
488
                if is_internal_key
208✔
489
                    && psbt.inputs[input_index].tap_key_sig.is_none()
104✔
490
                    && sign_options.sign_with_tap_internal_key
88✔
491
                    && x_only_pubkey == psbt_internal_key
88✔
492
                {
64✔
493
                    let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
80✔
494
                    sign_psbt_schnorr(
64✔
495
                        &self.inner,
64✔
496
                        x_only_pubkey,
64✔
497
                        None,
64✔
498
                        &mut psbt.inputs[input_index],
64✔
499
                        hash,
64✔
500
                        hash_ty,
64✔
501
                        secp,
64✔
502
                    );
64✔
503
                }
128✔
504
            }
×
505

506
            if let Some((leaf_hashes, _)) =
168✔
507
                psbt.inputs[input_index].tap_key_origins.get(&x_only_pubkey)
192✔
508
            {
509
                let leaf_hashes = leaf_hashes
168✔
510
                    .iter()
168✔
511
                    .filter(|lh| {
168✔
512
                        // Removing the leaves we shouldn't sign for
513
                        let should_sign = match &sign_options.tap_leaves_options {
104✔
514
                            TapLeavesOptions::All => true,
56✔
515
                            TapLeavesOptions::Include(v) => v.contains(lh),
16✔
516
                            TapLeavesOptions::Exclude(v) => !v.contains(lh),
16✔
517
                            TapLeavesOptions::None => false,
16✔
518
                        };
519
                        // Filtering out the leaves without our key
520
                        should_sign
104✔
521
                            && !psbt.inputs[input_index]
72✔
522
                                .tap_script_sigs
72✔
523
                                .contains_key(&(x_only_pubkey, **lh))
72✔
524
                    })
168✔
525
                    .cloned()
168✔
526
                    .collect::<Vec<_>>();
168✔
527
                for lh in leaf_hashes {
240✔
528
                    let (hash, hash_ty) = Tap::sighash(psbt, input_index, Some(lh))?;
72✔
529
                    sign_psbt_schnorr(
72✔
530
                        &self.inner,
72✔
531
                        x_only_pubkey,
72✔
532
                        Some(lh),
72✔
533
                        &mut psbt.inputs[input_index],
72✔
534
                        hash,
72✔
535
                        hash_ty,
72✔
536
                        secp,
72✔
537
                    );
72✔
538
                }
539
            }
24✔
540

541
            return Ok(());
192✔
542
        }
200✔
543

200✔
544
        if psbt.inputs[input_index].partial_sigs.contains_key(&pubkey) {
200✔
545
            return Ok(());
8✔
546
        }
192✔
547

548
        let (hash, hash_ty) = match self.ctx {
192✔
549
            SignerContext::Segwitv0 => {
550
                let (h, t) = Segwitv0::sighash(psbt, input_index, ())?;
184✔
551
                let h = h.to_raw_hash();
184✔
552
                (h, t)
184✔
553
            }
554
            SignerContext::Legacy => {
555
                let (h, t) = Legacy::sighash(psbt, input_index, ())?;
8✔
556
                let h = h.to_raw_hash();
8✔
557
                (h, t)
8✔
558
            }
559
            _ => return Ok(()), // handled above
×
560
        };
561
        sign_psbt_ecdsa(
192✔
562
            &self.inner,
192✔
563
            pubkey,
192✔
564
            &mut psbt.inputs[input_index],
192✔
565
            hash,
192✔
566
            hash_ty,
192✔
567
            secp,
192✔
568
            sign_options.allow_grinding,
192✔
569
        );
192✔
570

192✔
571
        Ok(())
192✔
572
    }
440✔
573
}
574

575
fn sign_psbt_ecdsa(
192✔
576
    secret_key: &secp256k1::SecretKey,
192✔
577
    pubkey: PublicKey,
192✔
578
    psbt_input: &mut psbt::Input,
192✔
579
    hash: impl bitcoin::hashes::Hash<Bytes = [u8; 32]>,
192✔
580
    sighash_type: EcdsaSighashType,
192✔
581
    secp: &SecpCtx,
192✔
582
    allow_grinding: bool,
192✔
583
) {
192✔
584
    let msg = &Message::from_digest(hash.to_byte_array());
192✔
585
    let signature = if allow_grinding {
192✔
586
        secp.sign_ecdsa_low_r(msg, secret_key)
184✔
587
    } else {
588
        secp.sign_ecdsa(msg, secret_key)
8✔
589
    };
590
    secp.verify_ecdsa(msg, &signature, &pubkey.inner)
192✔
591
        .expect("invalid or corrupted ecdsa signature");
192✔
592

192✔
593
    let final_signature = ecdsa::Signature {
192✔
594
        signature,
192✔
595
        sighash_type,
192✔
596
    };
192✔
597
    psbt_input.partial_sigs.insert(pubkey, final_signature);
192✔
598
}
192✔
599

600
// Calling this with `leaf_hash` = `None` will sign for key-spend
601
fn sign_psbt_schnorr(
136✔
602
    secret_key: &secp256k1::SecretKey,
136✔
603
    pubkey: XOnlyPublicKey,
136✔
604
    leaf_hash: Option<taproot::TapLeafHash>,
136✔
605
    psbt_input: &mut psbt::Input,
136✔
606
    hash: TapSighash,
136✔
607
    sighash_type: TapSighashType,
136✔
608
    secp: &SecpCtx,
136✔
609
) {
136✔
610
    let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
136✔
611
    let keypair = match leaf_hash {
136✔
612
        None => keypair
64✔
613
            .tap_tweak(secp, psbt_input.tap_merkle_root)
64✔
614
            .to_inner(),
64✔
615
        Some(_) => keypair, // no tweak for script spend
72✔
616
    };
617

618
    let msg = &Message::from(hash);
136✔
619
    let signature = secp.sign_schnorr(msg, &keypair);
136✔
620
    secp.verify_schnorr(&signature, msg, &XOnlyPublicKey::from_keypair(&keypair).0)
136✔
621
        .expect("invalid or corrupted schnorr signature");
136✔
622

136✔
623
    let final_signature = taproot::Signature {
136✔
624
        signature,
136✔
625
        sighash_type,
136✔
626
    };
136✔
627

628
    if let Some(lh) = leaf_hash {
136✔
629
        psbt_input
72✔
630
            .tap_script_sigs
72✔
631
            .insert((pubkey, lh), final_signature);
72✔
632
    } else {
72✔
633
        psbt_input.tap_key_sig = Some(final_signature);
64✔
634
    }
64✔
635
}
136✔
636

637
/// Defines the order in which signers are called
638
///
639
/// The default value is `100`. Signers with an ordering above that will be called later,
640
/// and they will thus see the partial signatures added to the transaction once they get to sign
641
/// themselves.
642
#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
643
pub struct SignerOrdering(pub usize);
644

645
impl Default for SignerOrdering {
646
    fn default() -> Self {
2,722✔
647
        SignerOrdering(100)
2,722✔
648
    }
2,722✔
649
}
650

651
#[derive(Debug, Clone)]
652
struct SignersContainerKey {
653
    id: SignerId,
654
    ordering: SignerOrdering,
655
}
656

657
impl From<(SignerId, SignerOrdering)> for SignersContainerKey {
658
    fn from(tuple: (SignerId, SignerOrdering)) -> Self {
8,251✔
659
        SignersContainerKey {
8,251✔
660
            id: tuple.0,
8,251✔
661
            ordering: tuple.1,
8,251✔
662
        }
8,251✔
663
    }
8,251✔
664
}
665

666
/// Container for multiple signers
667
#[derive(Debug, Default, Clone)]
668
pub struct SignersContainer(BTreeMap<SignersContainerKey, Arc<dyn TransactionSigner>>);
669

670
impl SignersContainer {
671
    /// Create a map of public keys to secret keys
672
    pub fn as_key_map(&self, secp: &SecpCtx) -> KeyMap {
28✔
673
        self.0
28✔
674
            .values()
28✔
675
            .filter_map(|signer| signer.descriptor_secret_key())
28✔
676
            .filter_map(|secret| secret.to_public(secp).ok().map(|public| (public, secret)))
28✔
677
            .collect()
28✔
678
    }
28✔
679

680
    /// Build a new signer container from a [`KeyMap`]
681
    ///
682
    /// Also looks at the corresponding descriptor to determine the [`SignerContext`] to attach to
683
    /// the signers
684
    pub fn build(
2,962✔
685
        keymap: KeyMap,
2,962✔
686
        descriptor: &Descriptor<DescriptorPublicKey>,
2,962✔
687
        secp: &SecpCtx,
2,962✔
688
    ) -> SignersContainer {
2,962✔
689
        let mut container = SignersContainer::new();
2,962✔
690

691
        for (pubkey, secret) in keymap {
5,636✔
692
            let ctx = match descriptor {
2,674✔
693
                Descriptor::Tr(tr) => SignerContext::Tap {
444✔
694
                    is_internal_key: tr.internal_key() == &pubkey,
444✔
695
                },
444✔
696
                _ if descriptor.is_witness() => SignerContext::Segwitv0,
2,230✔
697
                _ => SignerContext::Legacy,
77✔
698
            };
699

700
            match secret {
2,674✔
701
                DescriptorSecretKey::Single(private_key) => container.add_external(
1,168✔
702
                    SignerId::from(
1,168✔
703
                        private_key
1,168✔
704
                            .key
1,168✔
705
                            .public_key(secp)
1,168✔
706
                            .to_pubkeyhash(SigType::Ecdsa),
1,168✔
707
                    ),
1,168✔
708
                    SignerOrdering::default(),
1,168✔
709
                    Arc::new(SignerWrapper::new(private_key.key, ctx)),
1,168✔
710
                ),
1,168✔
711
                DescriptorSecretKey::XPrv(xprv) => container.add_external(
1,506✔
712
                    SignerId::from(xprv.root_fingerprint(secp)),
1,506✔
713
                    SignerOrdering::default(),
1,506✔
714
                    Arc::new(SignerWrapper::new(xprv, ctx)),
1,506✔
715
                ),
1,506✔
716
                DescriptorSecretKey::MultiXPrv(xprv) => container.add_external(
×
717
                    SignerId::from(xprv.root_fingerprint(secp)),
×
718
                    SignerOrdering::default(),
×
719
                    Arc::new(SignerWrapper::new(xprv, ctx)),
×
720
                ),
×
721
            };
722
        }
723

724
        container
2,962✔
725
    }
2,962✔
726
}
727

728
impl SignersContainer {
729
    /// Default constructor
730
    pub fn new() -> Self {
2,964✔
731
        SignersContainer(Default::default())
2,964✔
732
    }
2,964✔
733

734
    /// Adds an external signer to the container for the specified id. Optionally returns the
735
    /// signer that was previously in the container, if any
736
    pub fn add_external(
2,745✔
737
        &mut self,
2,745✔
738
        id: SignerId,
2,745✔
739
        ordering: SignerOrdering,
2,745✔
740
        signer: Arc<dyn TransactionSigner>,
2,745✔
741
    ) -> Option<Arc<dyn TransactionSigner>> {
2,745✔
742
        self.0.insert((id, ordering).into(), signer)
2,745✔
743
    }
2,745✔
744

745
    /// Removes a signer from the container and returns it
746
    pub fn remove(
×
747
        &mut self,
×
748
        id: SignerId,
×
749
        ordering: SignerOrdering,
×
750
    ) -> Option<Arc<dyn TransactionSigner>> {
×
751
        self.0.remove(&(id, ordering).into())
×
752
    }
×
753

754
    /// Returns the list of identifiers of all the signers in the container
755
    pub fn ids(&self) -> Vec<&SignerId> {
1✔
756
        self.0
1✔
757
            .keys()
1✔
758
            .map(|SignersContainerKey { id, .. }| id)
2✔
759
            .collect()
1✔
760
    }
1✔
761

762
    /// Returns the list of signers in the container, sorted by lowest to highest `ordering`
763
    pub fn signers(&self) -> Vec<&Arc<dyn TransactionSigner>> {
698✔
764
        self.0.values().collect()
698✔
765
    }
698✔
766

767
    /// Finds the signer with lowest ordering for a given id in the container.
768
    pub fn find(&self, id: SignerId) -> Option<&Arc<dyn TransactionSigner>> {
2,753✔
769
        self.0
2,753✔
770
            .range((
2,753✔
771
                Included(&(id.clone(), SignerOrdering(0)).into()),
2,753✔
772
                Included(&(id.clone(), SignerOrdering(usize::MAX)).into()),
2,753✔
773
            ))
2,753✔
774
            .filter(|(k, _)| k.id == id)
2,903✔
775
            .map(|(_, v)| v)
2,753✔
776
            .next()
2,753✔
777
    }
2,753✔
778
}
779

780
/// Options for a software signer
781
///
782
/// Adjust the behavior of our software signers and the way a transaction is finalized
783
#[derive(Debug, Clone)]
784
pub struct SignOptions {
785
    /// Whether the signer should trust the `witness_utxo`, if the `non_witness_utxo` hasn't been
786
    /// provided
787
    ///
788
    /// Defaults to `false` to mitigate the "SegWit bug" which should trick the wallet into
789
    /// paying a fee larger than expected.
790
    ///
791
    /// Some wallets, especially if relatively old, might not provide the `non_witness_utxo` for
792
    /// SegWit transactions in the PSBT they generate: in those cases setting this to `true`
793
    /// should correctly produce a signature, at the expense of an increased trust in the creator
794
    /// of the PSBT.
795
    ///
796
    /// 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>
797
    pub trust_witness_utxo: bool,
798

799
    /// Whether the wallet should assume a specific height has been reached when trying to finalize
800
    /// a transaction
801
    ///
802
    /// The wallet will only "use" a timelock to satisfy the spending policy of an input if the
803
    /// timelock height has already been reached. This option allows overriding the "current height" to let the
804
    /// wallet use timelocks in the future to spend a coin.
805
    pub assume_height: Option<u32>,
806

807
    /// Whether the signer should use the `sighash_type` set in the PSBT when signing, no matter
808
    /// what its value is
809
    ///
810
    /// Defaults to `false` which will only allow signing using `SIGHASH_ALL`.
811
    pub allow_all_sighashes: bool,
812

813
    /// Whether to remove partial signatures from the PSBT inputs while finalizing PSBT.
814
    ///
815
    /// Defaults to `true` which will remove partial signatures during finalization.
816
    pub remove_partial_sigs: bool,
817

818
    /// Whether to remove taproot specific fields from the PSBT on finalization.
819
    ///
820
    /// For inputs this includes the taproot internal key, merkle root, and individual
821
    /// scripts and signatures. For both inputs and outputs it includes key origin info.
822
    ///
823
    /// Defaults to `true` which will remove all of the above mentioned fields when finalizing.
824
    ///
825
    /// See [`BIP371`](https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki) for details.
826
    pub remove_taproot_extras: bool,
827

828
    /// Whether to try finalizing the PSBT after the inputs are signed.
829
    ///
830
    /// Defaults to `true` which will try finalizing PSBT after inputs are signed.
831
    pub try_finalize: bool,
832

833
    /// Specifies which Taproot script-spend leaves we should sign for. This option is
834
    /// ignored if we're signing a non-taproot PSBT.
835
    ///
836
    /// Defaults to All, i.e., the wallet will sign all the leaves it has a key for.
837
    pub tap_leaves_options: TapLeavesOptions,
838

839
    /// Whether we should try to sign a taproot transaction with the taproot internal key
840
    /// or not. This option is ignored if we're signing a non-taproot PSBT.
841
    ///
842
    /// Defaults to `true`, i.e., we always try to sign with the taproot internal key.
843
    pub sign_with_tap_internal_key: bool,
844

845
    /// Whether we should grind ECDSA signature to ensure signing with low r
846
    /// or not.
847
    /// Defaults to `true`, i.e., we always grind ECDSA signature to sign with low r.
848
    pub allow_grinding: bool,
849
}
850

851
/// Customize which taproot script-path leaves the signer should sign.
852
#[derive(Default, Debug, Clone, PartialEq, Eq)]
853
pub enum TapLeavesOptions {
854
    /// The signer will sign all the leaves it has a key for.
855
    #[default]
856
    All,
857
    /// The signer won't sign leaves other than the ones specified. Note that it could still ignore
858
    /// some of the specified leaves, if it doesn't have the right key to sign them.
859
    Include(Vec<taproot::TapLeafHash>),
860
    /// The signer won't sign the specified leaves.
861
    Exclude(Vec<taproot::TapLeafHash>),
862
    /// The signer won't sign any leaf.
863
    None,
864
}
865

866
impl Default for SignOptions {
867
    fn default() -> Self {
336✔
868
        SignOptions {
336✔
869
            trust_witness_utxo: false,
336✔
870
            assume_height: None,
336✔
871
            allow_all_sighashes: false,
336✔
872
            remove_partial_sigs: true,
336✔
873
            remove_taproot_extras: true,
336✔
874
            try_finalize: true,
336✔
875
            tap_leaves_options: TapLeavesOptions::default(),
336✔
876
            sign_with_tap_internal_key: true,
336✔
877
            allow_grinding: true,
336✔
878
        }
336✔
879
    }
336✔
880
}
881

882
pub(crate) trait ComputeSighash {
883
    type Extra;
884
    type Sighash;
885
    type SighashType;
886

887
    fn sighash(
888
        psbt: &Psbt,
889
        input_index: usize,
890
        extra: Self::Extra,
891
    ) -> Result<(Self::Sighash, Self::SighashType), SignerError>;
892
}
893

894
impl ComputeSighash for Legacy {
895
    type Extra = ();
896
    type Sighash = sighash::LegacySighash;
897
    type SighashType = EcdsaSighashType;
898

899
    fn sighash(
8✔
900
        psbt: &Psbt,
8✔
901
        input_index: usize,
8✔
902
        _extra: (),
8✔
903
    ) -> Result<(Self::Sighash, Self::SighashType), SignerError> {
8✔
904
        if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
8✔
905
            return Err(SignerError::InputIndexOutOfRange);
×
906
        }
8✔
907

8✔
908
        let psbt_input = &psbt.inputs[input_index];
8✔
909
        let tx_input = &psbt.unsigned_tx.input[input_index];
8✔
910

911
        let sighash = psbt_input
8✔
912
            .sighash_type
8✔
913
            .unwrap_or_else(|| EcdsaSighashType::All.into())
8✔
914
            .ecdsa_hash_ty()
8✔
915
            .map_err(|_| SignerError::InvalidSighash)?;
8✔
916
        let script = match psbt_input.redeem_script {
8✔
917
            Some(ref redeem_script) => redeem_script.clone(),
×
918
            None => {
919
                let non_witness_utxo = psbt_input
8✔
920
                    .non_witness_utxo
8✔
921
                    .as_ref()
8✔
922
                    .ok_or(SignerError::MissingNonWitnessUtxo)?;
8✔
923
                let prev_out = non_witness_utxo
8✔
924
                    .output
8✔
925
                    .get(tx_input.previous_output.vout as usize)
8✔
926
                    .ok_or(SignerError::InvalidNonWitnessUtxo)?;
8✔
927

928
                prev_out.script_pubkey.clone()
8✔
929
            }
930
        };
931

932
        Ok((
933
            sighash::SighashCache::new(&psbt.unsigned_tx).legacy_signature_hash(
8✔
934
                input_index,
8✔
935
                &script,
8✔
936
                sighash.to_u32(),
8✔
937
            )?,
8✔
938
            sighash,
8✔
939
        ))
940
    }
8✔
941
}
942

943
impl ComputeSighash for Segwitv0 {
944
    type Extra = ();
945
    type Sighash = sighash::SegwitV0Sighash;
946
    type SighashType = EcdsaSighashType;
947

948
    fn sighash(
184✔
949
        psbt: &Psbt,
184✔
950
        input_index: usize,
184✔
951
        _extra: (),
184✔
952
    ) -> Result<(Self::Sighash, Self::SighashType), SignerError> {
184✔
953
        if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
184✔
954
            return Err(SignerError::InputIndexOutOfRange);
×
955
        }
184✔
956

184✔
957
        let psbt_input = &psbt.inputs[input_index];
184✔
958
        let tx_input = &psbt.unsigned_tx.input[input_index];
184✔
959

960
        let sighash_type = psbt_input
184✔
961
            .sighash_type
184✔
962
            .unwrap_or_else(|| EcdsaSighashType::All.into())
184✔
963
            .ecdsa_hash_ty()
184✔
964
            .map_err(|_| SignerError::InvalidSighash)?;
184✔
965

966
        // Always try first with the non-witness utxo
967
        let utxo = if let Some(prev_tx) = &psbt_input.non_witness_utxo {
184✔
968
            // Check the provided prev-tx
969
            if prev_tx.compute_txid() != tx_input.previous_output.txid {
152✔
970
                return Err(SignerError::InvalidNonWitnessUtxo);
×
971
            }
152✔
972

152✔
973
            // The output should be present, if it's missing the `non_witness_utxo` is invalid
152✔
974
            prev_tx
152✔
975
                .output
152✔
976
                .get(tx_input.previous_output.vout as usize)
152✔
977
                .ok_or(SignerError::InvalidNonWitnessUtxo)?
152✔
978
        } else if let Some(witness_utxo) = &psbt_input.witness_utxo {
32✔
979
            // Fallback to the witness_utxo. If we aren't allowed to use it, signing should fail
980
            // before we get to this point
981
            witness_utxo
32✔
982
        } else {
983
            // Nothing has been provided
984
            return Err(SignerError::MissingNonWitnessUtxo);
×
985
        };
986
        let value = utxo.value;
184✔
987

184✔
988
        let mut sighasher = sighash::SighashCache::new(&psbt.unsigned_tx);
184✔
989

990
        let sighash = match psbt_input.witness_script {
184✔
991
            Some(ref witness_script) => {
×
992
                sighasher.p2wsh_signature_hash(input_index, witness_script, value, sighash_type)?
×
993
            }
994
            None => {
995
                if utxo.script_pubkey.is_p2wpkh() {
184✔
996
                    sighasher.p2wpkh_signature_hash(
176✔
997
                        input_index,
176✔
998
                        &utxo.script_pubkey,
176✔
999
                        value,
176✔
1000
                        sighash_type,
176✔
1001
                    )?
176✔
1002
                } else if psbt_input
8✔
1003
                    .redeem_script
8✔
1004
                    .as_ref()
8✔
1005
                    .map(|s| s.is_p2wpkh())
8✔
1006
                    .unwrap_or(false)
8✔
1007
                {
1008
                    let script_pubkey = psbt_input.redeem_script.as_ref().unwrap();
8✔
1009
                    sighasher.p2wpkh_signature_hash(
8✔
1010
                        input_index,
8✔
1011
                        script_pubkey,
8✔
1012
                        value,
8✔
1013
                        sighash_type,
8✔
1014
                    )?
8✔
1015
                } else {
1016
                    return Err(SignerError::MissingWitnessScript);
×
1017
                }
1018
            }
1019
        };
1020
        Ok((sighash, sighash_type))
184✔
1021
    }
184✔
1022
}
1023

1024
impl ComputeSighash for Tap {
1025
    type Extra = Option<taproot::TapLeafHash>;
1026
    type Sighash = TapSighash;
1027
    type SighashType = TapSighashType;
1028

1029
    fn sighash(
152✔
1030
        psbt: &Psbt,
152✔
1031
        input_index: usize,
152✔
1032
        extra: Self::Extra,
152✔
1033
    ) -> Result<(Self::Sighash, TapSighashType), SignerError> {
152✔
1034
        if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
152✔
1035
            return Err(SignerError::InputIndexOutOfRange);
×
1036
        }
152✔
1037

152✔
1038
        let psbt_input = &psbt.inputs[input_index];
152✔
1039

1040
        let sighash_type = psbt_input
152✔
1041
            .sighash_type
152✔
1042
            .unwrap_or_else(|| TapSighashType::Default.into())
152✔
1043
            .taproot_hash_ty()
152✔
1044
            .map_err(|_| SignerError::InvalidSighash)?;
152✔
1045
        let witness_utxos = (0..psbt.inputs.len())
152✔
1046
            .map(|i| psbt.get_utxo_for(i))
152✔
1047
            .collect::<Vec<_>>();
152✔
1048
        let mut all_witness_utxos = vec![];
152✔
1049

152✔
1050
        let mut cache = sighash::SighashCache::new(&psbt.unsigned_tx);
152✔
1051
        let is_anyone_can_pay = psbt::PsbtSighashType::from(sighash_type).to_u32() & 0x80 != 0;
152✔
1052
        let prevouts = if is_anyone_can_pay {
152✔
1053
            sighash::Prevouts::One(
1054
                input_index,
16✔
1055
                witness_utxos[input_index]
16✔
1056
                    .as_ref()
16✔
1057
                    .ok_or(SignerError::MissingWitnessUtxo)?,
16✔
1058
            )
1059
        } else if witness_utxos.iter().all(Option::is_some) {
136✔
1060
            all_witness_utxos.extend(witness_utxos.iter().filter_map(|x| x.as_ref()));
128✔
1061
            sighash::Prevouts::All(&all_witness_utxos)
128✔
1062
        } else {
1063
            return Err(SignerError::MissingWitnessUtxo);
8✔
1064
        };
1065

1066
        // Assume no OP_CODESEPARATOR
1067
        let extra = extra.map(|leaf_hash| (leaf_hash, 0xFFFFFFFF));
136✔
1068

136✔
1069
        Ok((
136✔
1070
            cache.taproot_signature_hash(input_index, &prevouts, None, extra, sighash_type)?,
136✔
1071
            sighash_type,
136✔
1072
        ))
1073
    }
152✔
1074
}
1075

1076
impl PartialOrd for SignersContainerKey {
1077
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2,701✔
1078
        Some(self.cmp(other))
2,701✔
1079
    }
2,701✔
1080
}
1081

1082
impl Ord for SignersContainerKey {
1083
    fn cmp(&self, other: &Self) -> Ordering {
8,583✔
1084
        self.ordering
8,583✔
1085
            .cmp(&other.ordering)
8,583✔
1086
            .then(self.id.cmp(&other.id))
8,583✔
1087
    }
8,583✔
1088
}
1089

1090
impl PartialEq for SignersContainerKey {
1091
    fn eq(&self, other: &Self) -> bool {
×
1092
        self.id == other.id && self.ordering == other.ordering
×
1093
    }
×
1094
}
1095

1096
impl Eq for SignersContainerKey {}
1097

1098
#[cfg(test)]
1099
mod signers_container_tests {
1100
    use super::*;
1101
    use crate::descriptor;
1102
    use crate::descriptor::IntoWalletDescriptor;
1103
    use crate::keys::{DescriptorKey, IntoDescriptorKey};
1104
    use assert_matches::assert_matches;
1105
    use bitcoin::bip32;
1106
    use bitcoin::secp256k1::{All, Secp256k1};
1107
    use bitcoin::Network;
1108
    use core::str::FromStr;
1109
    use miniscript::ScriptContext;
1110

1111
    fn is_equal(this: &Arc<dyn TransactionSigner>, that: &Arc<DummySigner>) -> bool {
7✔
1112
        let secp = Secp256k1::new();
7✔
1113
        this.id(&secp) == that.id(&secp)
7✔
1114
    }
7✔
1115

1116
    // Signers added with the same ordering (like `Ordering::default`) created from `KeyMap`
1117
    // should be preserved and not overwritten.
1118
    // This happens usually when a set of signers is created from a descriptor with private keys.
1119
    #[test]
1120
    fn signers_with_same_ordering() {
1✔
1121
        let secp = Secp256k1::new();
1✔
1122

1✔
1123
        let (prvkey1, _, _) = setup_keys(TPRV0_STR);
1✔
1124
        let (prvkey2, _, _) = setup_keys(TPRV1_STR);
1✔
1125
        let desc = descriptor!(sh(multi(2, prvkey1, prvkey2))).unwrap();
1✔
1126
        let (wallet_desc, keymap) = desc
1✔
1127
            .into_wallet_descriptor(&secp, Network::Testnet)
1✔
1128
            .unwrap();
1✔
1129

1✔
1130
        let signers = SignersContainer::build(keymap, &wallet_desc, &secp);
1✔
1131
        assert_eq!(signers.ids().len(), 2);
1✔
1132

1133
        let signers = signers.signers();
1✔
1134
        assert_eq!(signers.len(), 2);
1✔
1135
    }
1✔
1136

1137
    #[test]
1138
    fn signers_sorted_by_ordering() {
1✔
1139
        let mut signers = SignersContainer::new();
1✔
1140
        let signer1 = Arc::new(DummySigner { number: 1 });
1✔
1141
        let signer2 = Arc::new(DummySigner { number: 2 });
1✔
1142
        let signer3 = Arc::new(DummySigner { number: 3 });
1✔
1143

1✔
1144
        // Mixed order insertions verifies we are not inserting at head or tail.
1✔
1145
        signers.add_external(SignerId::Dummy(2), SignerOrdering(2), signer2.clone());
1✔
1146
        signers.add_external(SignerId::Dummy(1), SignerOrdering(1), signer1.clone());
1✔
1147
        signers.add_external(SignerId::Dummy(3), SignerOrdering(3), signer3.clone());
1✔
1148

1✔
1149
        // Check that signers are sorted from lowest to highest ordering
1✔
1150
        let signers = signers.signers();
1✔
1151

1✔
1152
        assert!(is_equal(signers[0], &signer1));
1✔
1153
        assert!(is_equal(signers[1], &signer2));
1✔
1154
        assert!(is_equal(signers[2], &signer3));
1✔
1155
    }
1✔
1156

1157
    #[test]
1158
    fn find_signer_by_id() {
1✔
1159
        let mut signers = SignersContainer::new();
1✔
1160
        let signer1 = Arc::new(DummySigner { number: 1 });
1✔
1161
        let signer2 = Arc::new(DummySigner { number: 2 });
1✔
1162
        let signer3 = Arc::new(DummySigner { number: 3 });
1✔
1163
        let signer4 = Arc::new(DummySigner { number: 3 }); // Same ID as `signer3` but will use lower ordering.
1✔
1164

1✔
1165
        let id1 = SignerId::Dummy(1);
1✔
1166
        let id2 = SignerId::Dummy(2);
1✔
1167
        let id3 = SignerId::Dummy(3);
1✔
1168
        let id_nonexistent = SignerId::Dummy(999);
1✔
1169

1✔
1170
        signers.add_external(id1.clone(), SignerOrdering(1), signer1.clone());
1✔
1171
        signers.add_external(id2.clone(), SignerOrdering(2), signer2.clone());
1✔
1172
        signers.add_external(id3.clone(), SignerOrdering(3), signer3.clone());
1✔
1173

1174
        assert_matches!(signers.find(id1), Some(signer) if is_equal(signer, &signer1));
1✔
1175
        assert_matches!(signers.find(id2), Some(signer) if is_equal(signer, &signer2));
1✔
1176
        assert_matches!(signers.find(id3.clone()), Some(signer) if is_equal(signer, &signer3));
1✔
1177

1✔
1178
        // The `signer4` has the same ID as `signer3` but lower ordering.
1✔
1179
        // It should be found by `id3` instead of `signer3`.
1✔
1180
        signers.add_external(id3.clone(), SignerOrdering(2), signer4.clone());
1✔
1181
        assert_matches!(signers.find(id3), Some(signer) if is_equal(signer, &signer4));
1✔
1182

1183
        // Can't find anything with ID that doesn't exist
1184
        assert_matches!(signers.find(id_nonexistent), None);
1✔
1185
    }
1✔
1186

1187
    #[derive(Debug, Clone, Copy)]
1188
    struct DummySigner {
1189
        number: u64,
1190
    }
1191

1192
    impl SignerCommon for DummySigner {
1193
        fn id(&self, _secp: &SecpCtx) -> SignerId {
14✔
1194
            SignerId::Dummy(self.number)
14✔
1195
        }
14✔
1196
    }
1197

1198
    impl TransactionSigner for DummySigner {
1199
        fn sign_transaction(
×
1200
            &self,
×
1201
            _psbt: &mut Psbt,
×
1202
            _sign_options: &SignOptions,
×
1203
            _secp: &SecpCtx,
×
1204
        ) -> Result<(), SignerError> {
×
1205
            Ok(())
×
1206
        }
×
1207
    }
1208

1209
    const TPRV0_STR:&str = "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf";
1210
    const TPRV1_STR:&str = "tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N";
1211

1212
    const PATH: &str = "m/44'/1'/0'/0";
1213

1214
    fn setup_keys<Ctx: ScriptContext>(
2✔
1215
        tprv: &str,
2✔
1216
    ) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
2✔
1217
        let secp: Secp256k1<All> = Secp256k1::new();
2✔
1218
        let path = bip32::DerivationPath::from_str(PATH).unwrap();
2✔
1219
        let tprv = bip32::Xpriv::from_str(tprv).unwrap();
2✔
1220
        let tpub = bip32::Xpub::from_priv(&secp, &tprv);
2✔
1221
        let fingerprint = tprv.fingerprint(&secp);
2✔
1222
        let prvkey = (tprv, path.clone()).into_descriptor_key().unwrap();
2✔
1223
        let pubkey = (tpub, path).into_descriptor_key().unwrap();
2✔
1224

2✔
1225
        (prvkey, pubkey, fingerprint)
2✔
1226
    }
2✔
1227
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc