|
| 1 | +//! Common signing utilities for bdk_wallet examples |
| 2 | +//! |
| 3 | +//! This module provides the `SignerWrapper` struct and related utilities |
| 4 | +//! that enable signing functionality for the wallet examples. These utilities |
| 5 | +//! wrap the KeyMap type to implement the GetKey trait, allowing examples |
| 6 | +//! to sign transactions and PSBTs. |
| 7 | +//! |
| 8 | +//! Note: This module is only required temporarily until miniscript 12.x is released, |
| 9 | +//! which will include signing capabilities for KeyMap natively. |
| 10 | +
|
| 11 | +use miniscript::descriptor::{DescriptorSecretKey, KeyMap}; |
| 12 | +use std::collections::BTreeMap; |
| 13 | + |
| 14 | +use bitcoin::{ |
| 15 | + key::Secp256k1, |
| 16 | + psbt::{GetKey, GetKeyError, KeyRequest}, |
| 17 | +}; |
| 18 | + |
| 19 | +#[derive(Debug, Clone)] |
| 20 | +/// A wrapper over the [`KeyMap`] type that has the `GetKey` trait implementation for signing. |
| 21 | +pub struct SignerWrapper { |
| 22 | + key_map: KeyMap, |
| 23 | +} |
| 24 | + |
| 25 | +impl SignerWrapper { |
| 26 | + /// Creates a new [`SignerWrapper`] for the given [`KeyMap`]. |
| 27 | + pub fn new(key_map: KeyMap) -> Self { |
| 28 | + Self { key_map } |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +impl GetKey for SignerWrapper { |
| 33 | + type Error = GetKeyError; |
| 34 | + |
| 35 | + fn get_key<C: bitcoin::secp256k1::Signing>( |
| 36 | + &self, |
| 37 | + key_request: KeyRequest, |
| 38 | + secp: &bitcoin::key::Secp256k1<C>, |
| 39 | + ) -> Result<Option<bitcoin::PrivateKey>, Self::Error> { |
| 40 | + for key_map in self.key_map.iter() { |
| 41 | + let (_, desc_sk) = key_map; |
| 42 | + let wrapper = DescriptorSecretKeyWrapper::new(desc_sk.clone()); |
| 43 | + match wrapper.get_key(key_request.clone(), secp) { |
| 44 | + Ok(Some(private_key)) => return Ok(Some(private_key)), |
| 45 | + Ok(None) => continue, |
| 46 | + // TODO: (@leonardo) how should we handle this ? |
| 47 | + // we can't error-out on this, because the valid signing key can be in the next |
| 48 | + // iterations. |
| 49 | + Err(_) => continue, |
| 50 | + } |
| 51 | + } |
| 52 | + Ok(None) |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +/// Wrapper for DescriptorSecretKey to implement GetKey trait |
| 57 | +pub struct DescriptorSecretKeyWrapper(DescriptorSecretKey); |
| 58 | + |
| 59 | +impl DescriptorSecretKeyWrapper { |
| 60 | + /// Creates a new DescriptorSecretKeyWrapper |
| 61 | + pub fn new(desc_sk: DescriptorSecretKey) -> Self { |
| 62 | + Self(desc_sk) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +impl GetKey for DescriptorSecretKeyWrapper { |
| 67 | + type Error = GetKeyError; |
| 68 | + |
| 69 | + fn get_key<C: bitcoin::secp256k1::Signing>( |
| 70 | + &self, |
| 71 | + key_request: KeyRequest, |
| 72 | + secp: &Secp256k1<C>, |
| 73 | + ) -> Result<Option<bitcoin::PrivateKey>, Self::Error> { |
| 74 | + match (&self.0, key_request) { |
| 75 | + (DescriptorSecretKey::Single(single_priv), key_request) => { |
| 76 | + let private_key = single_priv.key; |
| 77 | + let public_key = private_key.public_key(secp); |
| 78 | + let pubkey_map = BTreeMap::from([(public_key, private_key)]); |
| 79 | + return pubkey_map.get_key(key_request, secp); |
| 80 | + } |
| 81 | + (DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Pubkey(public_key)) => { |
| 82 | + let private_key = descriptor_xkey.xkey.private_key; |
| 83 | + let pk = private_key.public_key(secp); |
| 84 | + if public_key.inner.eq(&pk) { |
| 85 | + return Ok(Some( |
| 86 | + descriptor_xkey |
| 87 | + .xkey |
| 88 | + .derive_priv(secp, &descriptor_xkey.derivation_path) |
| 89 | + .map_err(GetKeyError::Bip32)? |
| 90 | + .to_priv(), |
| 91 | + )); |
| 92 | + } |
| 93 | + } |
| 94 | + ( |
| 95 | + DescriptorSecretKey::XPrv(descriptor_xkey), |
| 96 | + ref key_request @ KeyRequest::Bip32(ref key_source), |
| 97 | + ) => { |
| 98 | + if let Some(key) = descriptor_xkey.xkey.get_key(key_request.clone(), secp)? { |
| 99 | + return Ok(Some(key)); |
| 100 | + } |
| 101 | + |
| 102 | + if let Some(_derivation_path) = descriptor_xkey.matches(key_source, secp) { |
| 103 | + let (_fp, derivation_path) = key_source; |
| 104 | + |
| 105 | + if let Some((_fp, origin_derivation_path)) = &descriptor_xkey.origin { |
| 106 | + let derivation_path = &derivation_path[origin_derivation_path.len()..]; |
| 107 | + return Ok(Some( |
| 108 | + descriptor_xkey |
| 109 | + .xkey |
| 110 | + .derive_priv(secp, &derivation_path) |
| 111 | + .map_err(GetKeyError::Bip32)? |
| 112 | + .to_priv(), |
| 113 | + )); |
| 114 | + } else { |
| 115 | + return Ok(Some( |
| 116 | + descriptor_xkey |
| 117 | + .xkey |
| 118 | + .derive_priv(secp, derivation_path) |
| 119 | + .map_err(GetKeyError::Bip32)? |
| 120 | + .to_priv(), |
| 121 | + )); |
| 122 | + }; |
| 123 | + } |
| 124 | + } |
| 125 | + (DescriptorSecretKey::XPrv(_), KeyRequest::XOnlyPubkey(_)) => { |
| 126 | + return Err(GetKeyError::NotSupported) |
| 127 | + } |
| 128 | + (DescriptorSecretKey::MultiXPrv(_), _) => unimplemented!(), |
| 129 | + _ => unreachable!(), |
| 130 | + } |
| 131 | + Ok(None) |
| 132 | + } |
| 133 | +} |
0 commit comments