1use crate::collections::BTreeMap;
85use alloc::string::String;
86use alloc::sync::Arc;
87use alloc::vec::Vec;
88use core::cmp::Ordering;
89use core::fmt;
90use core::ops::{Bound::Included, Deref};
91
92use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv};
93use bitcoin::hashes::hash160;
94use bitcoin::secp256k1::Message;
95use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType};
96use bitcoin::{ecdsa, psbt, sighash, taproot};
97use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1};
98use bitcoin::{PrivateKey, Psbt, PublicKey};
99
100use miniscript::descriptor::{
101 Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey,
102 InnerXKey, KeyMap, SinglePriv, SinglePubKey,
103};
104use miniscript::{SigType, ToPublicKey};
105
106use super::utils::SecpCtx;
107use crate::descriptor::{DescriptorMeta, XKeyUtils};
108use crate::psbt::PsbtUtils;
109use crate::wallet::error::MiniscriptPsbtError;
110
111#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Hash)]
114pub enum SignerId {
115 PkHash(hash160::Hash),
117 Fingerprint(Fingerprint),
119 Dummy(u64),
121}
122
123impl From<hash160::Hash> for SignerId {
124 fn from(hash: hash160::Hash) -> SignerId {
125 SignerId::PkHash(hash)
126 }
127}
128
129impl From<Fingerprint> for SignerId {
130 fn from(fing: Fingerprint) -> SignerId {
131 SignerId::Fingerprint(fing)
132 }
133}
134
135#[derive(Debug)]
137pub enum SignerError {
138 MissingKey,
140 InvalidKey,
142 UserCanceled,
144 InputIndexOutOfRange,
146 MissingNonWitnessUtxo,
148 InvalidNonWitnessUtxo,
150 MissingWitnessUtxo,
152 MissingWitnessScript,
154 MissingHdKeypath,
156 NonStandardSighash,
162 InvalidSighash,
164 SighashTaproot(sighash::TaprootError),
166 Psbt(psbt::SignError),
168 MiniscriptPsbt(MiniscriptPsbtError),
170 External(String),
174}
175
176impl fmt::Display for SignerError {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 match self {
179 Self::MissingKey => write!(f, "Missing private key"),
180 Self::InvalidKey => write!(f, "The private key in use has the right fingerprint but derives differently than expected"),
181 Self::UserCanceled => write!(f, "The user canceled the operation"),
182 Self::InputIndexOutOfRange => write!(f, "Input index out of range"),
183 Self::MissingNonWitnessUtxo => write!(f, "Missing non-witness UTXO"),
184 Self::InvalidNonWitnessUtxo => write!(f, "Invalid non-witness UTXO"),
185 Self::MissingWitnessUtxo => write!(f, "Missing witness UTXO"),
186 Self::MissingWitnessScript => write!(f, "Missing witness script"),
187 Self::MissingHdKeypath => write!(f, "Missing fingerprint and derivation path"),
188 Self::NonStandardSighash => write!(f, "The psbt contains a non standard sighash"),
189 Self::InvalidSighash => write!(f, "Invalid SIGHASH for the signing context in use"),
190 Self::SighashTaproot(err) => write!(f, "Error while computing the hash to sign a Taproot input: {err}"),
191 Self::Psbt(err) => write!(f, "Error computing the sighash: {err}"),
192 Self::MiniscriptPsbt(err) => write!(f, "Miniscript PSBT error: {err}"),
193 Self::External(err) => write!(f, "{err}"),
194 }
195 }
196}
197
198#[cfg(feature = "std")]
199impl std::error::Error for SignerError {}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205pub enum SignerContext {
206 Legacy,
208 Segwitv0,
210 Tap {
212 is_internal_key: bool,
214 },
215}
216
217#[derive(Debug, Clone)]
219pub struct SignerWrapper<S: Sized + fmt::Debug + Clone> {
220 signer: S,
221 ctx: SignerContext,
222}
223
224impl<S: Sized + fmt::Debug + Clone> SignerWrapper<S> {
225 pub fn new(signer: S, ctx: SignerContext) -> Self {
227 SignerWrapper { signer, ctx }
228 }
229}
230
231impl<S: Sized + fmt::Debug + Clone> Deref for SignerWrapper<S> {
232 type Target = S;
233
234 fn deref(&self) -> &Self::Target {
235 &self.signer
236 }
237}
238
239pub trait SignerCommon: fmt::Debug + Send + Sync {
241 fn id(&self, secp: &SecpCtx) -> SignerId;
246
247 fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
253 None
254 }
255}
256
257pub trait InputSigner: SignerCommon {
263 fn sign_input(
265 &self,
266 psbt: &mut Psbt,
267 input_index: usize,
268 sign_options: &SignOptions,
269 secp: &SecpCtx,
270 ) -> Result<(), SignerError>;
271}
272
273pub trait TransactionSigner: SignerCommon {
278 fn sign_transaction(
280 &self,
281 psbt: &mut Psbt,
282 sign_options: &SignOptions,
283 secp: &SecpCtx,
284 ) -> Result<(), SignerError>;
285}
286
287impl<T: InputSigner> TransactionSigner for T {
288 fn sign_transaction(
289 &self,
290 psbt: &mut Psbt,
291 sign_options: &SignOptions,
292 secp: &SecpCtx,
293 ) -> Result<(), SignerError> {
294 for input_index in 0..psbt.inputs.len() {
295 self.sign_input(psbt, input_index, sign_options, secp)?;
296 }
297
298 Ok(())
299 }
300}
301
302impl SignerCommon for SignerWrapper<DescriptorXKey<Xpriv>> {
303 fn id(&self, secp: &SecpCtx) -> SignerId {
304 SignerId::from(self.root_fingerprint(secp))
305 }
306
307 fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
308 Some(DescriptorSecretKey::XPrv(self.signer.clone()))
309 }
310}
311
312impl InputSigner for SignerWrapper<DescriptorXKey<Xpriv>> {
313 fn sign_input(
314 &self,
315 psbt: &mut Psbt,
316 input_index: usize,
317 sign_options: &SignOptions,
318 secp: &SecpCtx,
319 ) -> Result<(), SignerError> {
320 if input_index >= psbt.inputs.len() {
321 return Err(SignerError::InputIndexOutOfRange);
322 }
323
324 if psbt.inputs[input_index].final_script_sig.is_some()
325 || psbt.inputs[input_index].final_script_witness.is_some()
326 {
327 return Ok(());
328 }
329
330 let tap_key_origins = psbt.inputs[input_index]
331 .tap_key_origins
332 .iter()
333 .map(|(pk, (_, keysource))| (SinglePubKey::XOnly(*pk), keysource));
334 let (public_key, full_path) = match psbt.inputs[input_index]
335 .bip32_derivation
336 .iter()
337 .map(|(pk, keysource)| (SinglePubKey::FullKey(PublicKey::new(*pk)), keysource))
338 .chain(tap_key_origins)
339 .find_map(|(pk, keysource)| {
340 if self.matches(keysource, secp).is_some() {
341 Some((pk, keysource.1.clone()))
342 } else {
343 None
344 }
345 }) {
346 Some((pk, full_path)) => (pk, full_path),
347 None => return Ok(()),
348 };
349
350 let derived_key = match self.origin.clone() {
351 Some((_fingerprint, origin_path)) => {
352 let deriv_path = DerivationPath::from(
353 &full_path.into_iter().cloned().collect::<Vec<ChildNumber>>()
354 [origin_path.len()..],
355 );
356 self.xkey.derive_priv(secp, &deriv_path).unwrap()
357 }
358 None => self.xkey.derive_priv(secp, &full_path).unwrap(),
359 };
360
361 let computed_pk = secp256k1::PublicKey::from_secret_key(secp, &derived_key.private_key);
362 let valid_key = match public_key {
363 SinglePubKey::FullKey(pk) if pk.inner == computed_pk => true,
364 SinglePubKey::XOnly(x_only) if XOnlyPublicKey::from(computed_pk) == x_only => true,
365 _ => false,
366 };
367 if !valid_key {
368 Err(SignerError::InvalidKey)
369 } else {
370 let priv_key = PrivateKey {
372 compressed: true,
373 network: self.xkey.network,
374 inner: derived_key.private_key,
375 };
376
377 SignerWrapper::new(priv_key, self.ctx).sign_input(psbt, input_index, sign_options, secp)
378 }
379 }
380}
381
382fn multikey_to_xkeys<K: InnerXKey + Clone>(
383 multikey: DescriptorMultiXKey<K>,
384) -> Vec<DescriptorXKey<K>> {
385 multikey
386 .derivation_paths
387 .into_paths()
388 .into_iter()
389 .map(|derivation_path| DescriptorXKey {
390 origin: multikey.origin.clone(),
391 xkey: multikey.xkey.clone(),
392 derivation_path,
393 wildcard: multikey.wildcard,
394 })
395 .collect()
396}
397
398impl SignerCommon for SignerWrapper<DescriptorMultiXKey<Xpriv>> {
399 fn id(&self, secp: &SecpCtx) -> SignerId {
400 SignerId::from(self.root_fingerprint(secp))
401 }
402
403 fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
404 Some(DescriptorSecretKey::MultiXPrv(self.signer.clone()))
405 }
406}
407
408impl InputSigner for SignerWrapper<DescriptorMultiXKey<Xpriv>> {
409 fn sign_input(
410 &self,
411 psbt: &mut Psbt,
412 input_index: usize,
413 sign_options: &SignOptions,
414 secp: &SecpCtx,
415 ) -> Result<(), SignerError> {
416 let xkeys = multikey_to_xkeys(self.signer.clone());
417 for xkey in xkeys {
418 SignerWrapper::new(xkey, self.ctx).sign_input(psbt, input_index, sign_options, secp)?
419 }
420 Ok(())
421 }
422}
423
424impl SignerCommon for SignerWrapper<PrivateKey> {
425 fn id(&self, secp: &SecpCtx) -> SignerId {
426 SignerId::from(self.public_key(secp).to_pubkeyhash(SigType::Ecdsa))
427 }
428
429 fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
430 Some(DescriptorSecretKey::Single(SinglePriv {
431 key: self.signer,
432 origin: None,
433 }))
434 }
435}
436
437impl InputSigner for SignerWrapper<PrivateKey> {
438 fn sign_input(
439 &self,
440 psbt: &mut Psbt,
441 input_index: usize,
442 sign_options: &SignOptions,
443 secp: &SecpCtx,
444 ) -> Result<(), SignerError> {
445 if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
446 return Err(SignerError::InputIndexOutOfRange);
447 }
448
449 if psbt.inputs[input_index].final_script_sig.is_some()
450 || psbt.inputs[input_index].final_script_witness.is_some()
451 {
452 return Ok(());
453 }
454
455 let pubkey = PublicKey::from_private_key(secp, self);
456
457 match self.ctx {
458 SignerContext::Tap { is_internal_key } => {
459 let x_only_pubkey = XOnlyPublicKey::from(pubkey.inner);
460
461 if let Some(psbt_internal_key) = psbt.inputs[input_index].tap_internal_key {
462 if is_internal_key
463 && psbt.inputs[input_index].tap_key_sig.is_none()
464 && sign_options.sign_with_tap_internal_key
465 && x_only_pubkey == psbt_internal_key
466 {
467 let (sighash, sighash_type) = compute_tap_sighash(psbt, input_index, None)?;
468 sign_psbt_schnorr(
469 &self.inner,
470 x_only_pubkey,
471 None,
472 &mut psbt.inputs[input_index],
473 sighash,
474 sighash_type,
475 secp,
476 );
477 }
478 }
479
480 if let Some((leaf_hashes, _)) =
481 psbt.inputs[input_index].tap_key_origins.get(&x_only_pubkey)
482 {
483 let leaf_hashes = leaf_hashes
484 .iter()
485 .filter(|lh| {
486 let should_sign = match &sign_options.tap_leaves_options {
488 TapLeavesOptions::All => true,
489 TapLeavesOptions::Include(v) => v.contains(lh),
490 TapLeavesOptions::Exclude(v) => !v.contains(lh),
491 TapLeavesOptions::None => false,
492 };
493 should_sign
495 && !psbt.inputs[input_index]
496 .tap_script_sigs
497 .contains_key(&(x_only_pubkey, **lh))
498 })
499 .cloned()
500 .collect::<Vec<_>>();
501 for lh in leaf_hashes {
502 let (sighash, sighash_type) =
503 compute_tap_sighash(psbt, input_index, Some(lh))?;
504 sign_psbt_schnorr(
505 &self.inner,
506 x_only_pubkey,
507 Some(lh),
508 &mut psbt.inputs[input_index],
509 sighash,
510 sighash_type,
511 secp,
512 );
513 }
514 }
515 }
516 SignerContext::Segwitv0 | SignerContext::Legacy => {
517 if psbt.inputs[input_index].partial_sigs.contains_key(&pubkey) {
518 return Ok(());
519 }
520
521 let mut sighasher = sighash::SighashCache::new(psbt.unsigned_tx.clone());
522 let (msg, sighash_type) = psbt
523 .sighash_ecdsa(input_index, &mut sighasher)
524 .map_err(SignerError::Psbt)?;
525
526 sign_psbt_ecdsa(
527 &self.inner,
528 pubkey,
529 &mut psbt.inputs[input_index],
530 &msg,
531 sighash_type,
532 secp,
533 sign_options.allow_grinding,
534 );
535 }
536 }
537
538 Ok(())
539 }
540}
541
542fn sign_psbt_ecdsa(
543 secret_key: &secp256k1::SecretKey,
544 pubkey: PublicKey,
545 psbt_input: &mut psbt::Input,
546 msg: &Message,
547 sighash_type: EcdsaSighashType,
548 secp: &SecpCtx,
549 allow_grinding: bool,
550) {
551 let signature = if allow_grinding {
552 secp.sign_ecdsa_low_r(msg, secret_key)
553 } else {
554 secp.sign_ecdsa(msg, secret_key)
555 };
556 secp.verify_ecdsa(msg, &signature, &pubkey.inner)
557 .expect("invalid or corrupted ecdsa signature");
558
559 let final_signature = ecdsa::Signature {
560 signature,
561 sighash_type,
562 };
563 psbt_input.partial_sigs.insert(pubkey, final_signature);
564}
565
566fn sign_psbt_schnorr(
568 secret_key: &secp256k1::SecretKey,
569 pubkey: XOnlyPublicKey,
570 leaf_hash: Option<taproot::TapLeafHash>,
571 psbt_input: &mut psbt::Input,
572 sighash: TapSighash,
573 sighash_type: TapSighashType,
574 secp: &SecpCtx,
575) {
576 let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
577 let keypair = match leaf_hash {
578 None => keypair
579 .tap_tweak(secp, psbt_input.tap_merkle_root)
580 .to_keypair(),
581 Some(_) => keypair, };
583
584 let msg = &Message::from(sighash);
585 let signature = secp.sign_schnorr_no_aux_rand(msg, &keypair);
586 secp.verify_schnorr(&signature, msg, &XOnlyPublicKey::from_keypair(&keypair).0)
587 .expect("invalid or corrupted schnorr signature");
588
589 let final_signature = taproot::Signature {
590 signature,
591 sighash_type,
592 };
593
594 if let Some(lh) = leaf_hash {
595 psbt_input
596 .tap_script_sigs
597 .insert((pubkey, lh), final_signature);
598 } else {
599 psbt_input.tap_key_sig = Some(final_signature);
600 }
601}
602
603#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
609pub struct SignerOrdering(pub usize);
610
611impl Default for SignerOrdering {
612 fn default() -> Self {
613 SignerOrdering(100)
614 }
615}
616
617#[derive(Debug, Clone)]
618struct SignersContainerKey {
619 id: SignerId,
620 ordering: SignerOrdering,
621}
622
623impl From<(SignerId, SignerOrdering)> for SignersContainerKey {
624 fn from(tuple: (SignerId, SignerOrdering)) -> Self {
625 SignersContainerKey {
626 id: tuple.0,
627 ordering: tuple.1,
628 }
629 }
630}
631
632#[derive(Debug, Default, Clone)]
634pub struct SignersContainer(BTreeMap<SignersContainerKey, Arc<dyn TransactionSigner>>);
635
636impl SignersContainer {
637 pub fn as_key_map(&self, secp: &SecpCtx) -> KeyMap {
639 self.0
640 .values()
641 .filter_map(|signer| signer.descriptor_secret_key())
642 .filter_map(|secret| secret.to_public(secp).ok().map(|public| (public, secret)))
643 .collect()
644 }
645
646 pub fn build(
651 keymap: KeyMap,
652 descriptor: &Descriptor<DescriptorPublicKey>,
653 secp: &SecpCtx,
654 ) -> SignersContainer {
655 let mut container = SignersContainer::new();
656
657 for (pubkey, secret) in keymap {
658 let ctx = match descriptor {
659 Descriptor::Tr(tr) => SignerContext::Tap {
660 is_internal_key: tr.internal_key() == &pubkey,
661 },
662 _ if descriptor.is_witness() => SignerContext::Segwitv0,
663 _ => SignerContext::Legacy,
664 };
665
666 match secret {
667 DescriptorSecretKey::Single(private_key) => container.add_external(
668 SignerId::from(
669 private_key
670 .key
671 .public_key(secp)
672 .to_pubkeyhash(SigType::Ecdsa),
673 ),
674 SignerOrdering::default(),
675 Arc::new(SignerWrapper::new(private_key.key, ctx)),
676 ),
677 DescriptorSecretKey::XPrv(xprv) => container.add_external(
678 SignerId::from(xprv.root_fingerprint(secp)),
679 SignerOrdering::default(),
680 Arc::new(SignerWrapper::new(xprv, ctx)),
681 ),
682 DescriptorSecretKey::MultiXPrv(xprv) => container.add_external(
683 SignerId::from(xprv.root_fingerprint(secp)),
684 SignerOrdering::default(),
685 Arc::new(SignerWrapper::new(xprv, ctx)),
686 ),
687 };
688 }
689
690 container
691 }
692}
693
694impl SignersContainer {
695 pub fn new() -> Self {
697 SignersContainer(Default::default())
698 }
699
700 pub fn add_external(
703 &mut self,
704 id: SignerId,
705 ordering: SignerOrdering,
706 signer: Arc<dyn TransactionSigner>,
707 ) -> Option<Arc<dyn TransactionSigner>> {
708 self.0.insert((id, ordering).into(), signer)
709 }
710
711 pub fn remove(
713 &mut self,
714 id: SignerId,
715 ordering: SignerOrdering,
716 ) -> Option<Arc<dyn TransactionSigner>> {
717 self.0.remove(&(id, ordering).into())
718 }
719
720 pub fn ids(&self) -> Vec<&SignerId> {
722 self.0
723 .keys()
724 .map(|SignersContainerKey { id, .. }| id)
725 .collect()
726 }
727
728 pub fn signers(&self) -> Vec<&Arc<dyn TransactionSigner>> {
730 self.0.values().collect()
731 }
732
733 pub fn find(&self, id: SignerId) -> Option<&Arc<dyn TransactionSigner>> {
735 self.0
736 .range((
737 Included(&(id.clone(), SignerOrdering(0)).into()),
738 Included(&(id.clone(), SignerOrdering(usize::MAX)).into()),
739 ))
740 .filter(|(k, _)| k.id == id)
741 .map(|(_, v)| v)
742 .next()
743 }
744}
745
746#[derive(Debug, Clone)]
750pub struct SignOptions {
751 pub trust_witness_utxo: bool,
764
765 pub assume_height: Option<u32>,
772
773 pub allow_all_sighashes: bool,
778
779 pub try_finalize: bool,
783
784 pub tap_leaves_options: TapLeavesOptions,
789
790 pub sign_with_tap_internal_key: bool,
795
796 pub allow_grinding: bool,
800}
801
802#[derive(Default, Debug, Clone, PartialEq, Eq)]
804pub enum TapLeavesOptions {
805 #[default]
807 All,
808 Include(Vec<taproot::TapLeafHash>),
811 Exclude(Vec<taproot::TapLeafHash>),
813 None,
815}
816
817impl Default for SignOptions {
818 fn default() -> Self {
819 SignOptions {
820 trust_witness_utxo: false,
821 assume_height: None,
822 allow_all_sighashes: false,
823 try_finalize: true,
824 tap_leaves_options: TapLeavesOptions::default(),
825 sign_with_tap_internal_key: true,
826 allow_grinding: true,
827 }
828 }
829}
830
831fn compute_tap_sighash(
833 psbt: &Psbt,
834 input_index: usize,
835 extra: Option<taproot::TapLeafHash>,
836) -> Result<(sighash::TapSighash, TapSighashType), SignerError> {
837 if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
838 return Err(SignerError::InputIndexOutOfRange);
839 }
840
841 let psbt_input = &psbt.inputs[input_index];
842
843 let sighash_type = psbt_input
844 .sighash_type
845 .unwrap_or_else(|| TapSighashType::Default.into())
846 .taproot_hash_ty()
847 .map_err(|_| SignerError::InvalidSighash)?;
848 let witness_utxos = (0..psbt.inputs.len())
849 .map(|i| psbt.get_utxo_for(i))
850 .collect::<Vec<_>>();
851 let mut all_witness_utxos = vec![];
852
853 let mut cache = sighash::SighashCache::new(&psbt.unsigned_tx);
854 let is_anyone_can_pay = psbt::PsbtSighashType::from(sighash_type).to_u32() & 0x80 != 0;
855 let prevouts = if is_anyone_can_pay {
856 sighash::Prevouts::One(
857 input_index,
858 witness_utxos[input_index]
859 .as_ref()
860 .ok_or(SignerError::MissingWitnessUtxo)?,
861 )
862 } else if witness_utxos.iter().all(Option::is_some) {
863 all_witness_utxos.extend(witness_utxos.iter().filter_map(|x| x.as_ref()));
864 sighash::Prevouts::All(&all_witness_utxos)
865 } else {
866 return Err(SignerError::MissingWitnessUtxo);
867 };
868
869 let extra = extra.map(|leaf_hash| (leaf_hash, 0xFFFFFFFF));
871
872 Ok((
873 cache
874 .taproot_signature_hash(input_index, &prevouts, None, extra, sighash_type)
875 .map_err(SignerError::SighashTaproot)?,
876 sighash_type,
877 ))
878}
879
880impl PartialOrd for SignersContainerKey {
881 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
882 Some(self.cmp(other))
883 }
884}
885
886impl Ord for SignersContainerKey {
887 fn cmp(&self, other: &Self) -> Ordering {
888 self.ordering
889 .cmp(&other.ordering)
890 .then(self.id.cmp(&other.id))
891 }
892}
893
894impl PartialEq for SignersContainerKey {
895 fn eq(&self, other: &Self) -> bool {
896 self.id == other.id && self.ordering == other.ordering
897 }
898}
899
900impl Eq for SignersContainerKey {}
901
902#[cfg(test)]
903mod signers_container_tests {
904 use super::*;
905 use crate::descriptor;
906 use crate::descriptor::IntoWalletDescriptor;
907 use crate::keys::{DescriptorKey, IntoDescriptorKey};
908 use assert_matches::assert_matches;
909 use bitcoin::bip32;
910 use bitcoin::secp256k1::{All, Secp256k1};
911 use bitcoin::Network;
912 use core::str::FromStr;
913 use miniscript::ScriptContext;
914
915 fn is_equal(this: &Arc<dyn TransactionSigner>, that: &Arc<DummySigner>) -> bool {
916 let secp = Secp256k1::new();
917 this.id(&secp) == that.id(&secp)
918 }
919
920 #[test]
924 fn signers_with_same_ordering() {
925 let secp = Secp256k1::new();
926
927 let (prvkey1, _, _) = setup_keys(TPRV0_STR);
928 let (prvkey2, _, _) = setup_keys(TPRV1_STR);
929 let desc = descriptor!(sh(multi(2, prvkey1, prvkey2))).unwrap();
930 let (wallet_desc, keymap) = desc
931 .into_wallet_descriptor(&secp, Network::Testnet)
932 .unwrap();
933
934 let signers = SignersContainer::build(keymap, &wallet_desc, &secp);
935 assert_eq!(signers.ids().len(), 2);
936
937 let signers = signers.signers();
938 assert_eq!(signers.len(), 2);
939 }
940
941 #[test]
942 fn signers_sorted_by_ordering() {
943 let mut signers = SignersContainer::new();
944 let signer1 = Arc::new(DummySigner { number: 1 });
945 let signer2 = Arc::new(DummySigner { number: 2 });
946 let signer3 = Arc::new(DummySigner { number: 3 });
947
948 signers.add_external(SignerId::Dummy(2), SignerOrdering(2), signer2.clone());
950 signers.add_external(SignerId::Dummy(1), SignerOrdering(1), signer1.clone());
951 signers.add_external(SignerId::Dummy(3), SignerOrdering(3), signer3.clone());
952
953 let signers = signers.signers();
955
956 assert!(is_equal(signers[0], &signer1));
957 assert!(is_equal(signers[1], &signer2));
958 assert!(is_equal(signers[2], &signer3));
959 }
960
961 #[test]
962 fn find_signer_by_id() {
963 let mut signers = SignersContainer::new();
964 let signer1 = Arc::new(DummySigner { number: 1 });
965 let signer2 = Arc::new(DummySigner { number: 2 });
966 let signer3 = Arc::new(DummySigner { number: 3 });
967 let signer4 = Arc::new(DummySigner { number: 3 }); let id1 = SignerId::Dummy(1);
970 let id2 = SignerId::Dummy(2);
971 let id3 = SignerId::Dummy(3);
972 let id_nonexistent = SignerId::Dummy(999);
973
974 signers.add_external(id1.clone(), SignerOrdering(1), signer1.clone());
975 signers.add_external(id2.clone(), SignerOrdering(2), signer2.clone());
976 signers.add_external(id3.clone(), SignerOrdering(3), signer3.clone());
977
978 assert_matches!(signers.find(id1), Some(signer) if is_equal(signer, &signer1));
979 assert_matches!(signers.find(id2), Some(signer) if is_equal(signer, &signer2));
980 assert_matches!(signers.find(id3.clone()), Some(signer) if is_equal(signer, &signer3));
981
982 signers.add_external(id3.clone(), SignerOrdering(2), signer4.clone());
985 assert_matches!(signers.find(id3), Some(signer) if is_equal(signer, &signer4));
986
987 assert_matches!(signers.find(id_nonexistent), None);
989 }
990
991 #[derive(Debug, Clone, Copy)]
992 struct DummySigner {
993 number: u64,
994 }
995
996 impl SignerCommon for DummySigner {
997 fn id(&self, _secp: &SecpCtx) -> SignerId {
998 SignerId::Dummy(self.number)
999 }
1000 }
1001
1002 impl TransactionSigner for DummySigner {
1003 fn sign_transaction(
1004 &self,
1005 _psbt: &mut Psbt,
1006 _sign_options: &SignOptions,
1007 _secp: &SecpCtx,
1008 ) -> Result<(), SignerError> {
1009 Ok(())
1010 }
1011 }
1012
1013 const TPRV0_STR:&str = "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf";
1014 const TPRV1_STR:&str = "tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N";
1015
1016 const PATH: &str = "m/44'/1'/0'/0";
1017
1018 fn setup_keys<Ctx: ScriptContext>(
1019 tprv: &str,
1020 ) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
1021 let secp: Secp256k1<All> = Secp256k1::new();
1022 let path = bip32::DerivationPath::from_str(PATH).unwrap();
1023 let tprv = bip32::Xpriv::from_str(tprv).unwrap();
1024 let tpub = bip32::Xpub::from_priv(&secp, &tprv);
1025 let fingerprint = tprv.fingerprint(&secp);
1026 let prvkey = (tprv, path.clone()).into_descriptor_key().unwrap();
1027 let pubkey = (tpub, path).into_descriptor_key().unwrap();
1028
1029 (prvkey, pubkey, fingerprint)
1030 }
1031}