diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 817d0028..88831d38 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -3316,6 +3316,23 @@ mod test { assert_eq!(extracted.input[0].witness.len(), 2); } + #[test] + fn test_sign_single_xprv_with_master_fingerprint_and_path() { + let (wallet, _, _) = get_funded_wallet("wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let addr = wallet.get_new_address().unwrap(); + let mut builder = wallet.build_tx(); + builder + .set_single_recipient(addr.script_pubkey()) + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); + + let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap(); + assert_eq!(finalized, true); + + let extracted = signed_psbt.extract_tx(); + assert_eq!(extracted.input[0].witness.len(), 2); + } + #[test] fn test_sign_single_xprv_bip44_path() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)"); diff --git a/src/wallet/signer.rs b/src/wallet/signer.rs index 0dc22413..16f9af30 100644 --- a/src/wallet/signer.rs +++ b/src/wallet/signer.rs @@ -92,7 +92,7 @@ use bitcoin::blockdata::opcodes; use bitcoin::blockdata::script::Builder as ScriptBuilder; use bitcoin::hashes::{hash160, Hash}; use bitcoin::secp256k1::{Message, Secp256k1}; -use bitcoin::util::bip32::{ExtendedPrivKey, Fingerprint}; +use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint}; use bitcoin::util::{bip143, psbt}; use bitcoin::{PrivateKey, Script, SigHash, SigHashType}; @@ -206,7 +206,7 @@ impl Signer for DescriptorXKey { return Err(SignerError::InputIndexOutOfRange); } - let (public_key, deriv_path) = match psbt.inputs[input_index] + let (public_key, full_path) = match psbt.inputs[input_index] .bip32_derivation .iter() .filter_map(|(pk, &(fingerprint, ref path))| { @@ -222,7 +222,17 @@ impl Signer for DescriptorXKey { None => return Ok(()), }; - let derived_key = self.xkey.derive_priv(&secp, &deriv_path).unwrap(); + let derived_key = match self.origin.clone() { + Some((_fingerprint, origin_path)) => { + let deriv_path = DerivationPath::from( + &full_path.into_iter().cloned().collect::>() + [origin_path.len()..], + ); + self.xkey.derive_priv(&secp, &deriv_path).unwrap() + } + None => self.xkey.derive_priv(&secp, &full_path).unwrap(), + }; + if &derived_key.private_key.public_key(&secp) != public_key { Err(SignerError::InvalidKey) } else {