From 396ffb42f913d4dafb20eafa1fbfb21093715b2e Mon Sep 17 00:00:00 2001 From: davemo88 Date: Thu, 11 Mar 2021 17:39:02 -0500 Subject: [PATCH 1/3] handle descriptor xkey origin --- src/wallet/mod.rs | 17 +++++++++++++++++ src/wallet/signer.rs | 20 +++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) 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..f8efb844 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,21 @@ 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, path)) => { + let split_origin_path: Vec<&ChildNumber> = path.into_iter().collect(); + let mut deriv_path = DerivationPath::default(); + for (i, child) in full_path.into_iter().cloned().enumerate() { + match split_origin_path.get(i) { + Some(_) => continue, + None => deriv_path = deriv_path.extend(&[child]), + } + } + 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 { From 201bd6ee02bc38c02713b123781dda431a0609a1 Mon Sep 17 00:00:00 2001 From: davemo88 Date: Thu, 11 Mar 2021 21:35:16 -0500 Subject: [PATCH 2/3] better derivation path building --- src/wallet/signer.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/wallet/signer.rs b/src/wallet/signer.rs index f8efb844..3ff02425 100644 --- a/src/wallet/signer.rs +++ b/src/wallet/signer.rs @@ -223,15 +223,21 @@ impl Signer for DescriptorXKey { }; let derived_key = match self.origin.clone() { - Some((_fingerprint, path)) => { - let split_origin_path: Vec<&ChildNumber> = path.into_iter().collect(); - let mut deriv_path = DerivationPath::default(); - for (i, child) in full_path.into_iter().cloned().enumerate() { - match split_origin_path.get(i) { - Some(_) => continue, - None => deriv_path = deriv_path.extend(&[child]), - } - } + Some((_fingerprint, origin_path)) => { + let deriv_path = DerivationPath::from( + full_path + .into_iter() + .enumerate() + .filter_map(|(i, child)| { + if i >= origin_path.len() { + Some(child) + } else { + None + } + }) + .cloned() + .collect::>(), + ); self.xkey.derive_priv(&secp, &deriv_path).unwrap() } None => self.xkey.derive_priv(&secp, &full_path).unwrap(), From dc83db273aa348e4070d31c7b772c306d5b200e9 Mon Sep 17 00:00:00 2001 From: davemo88 Date: Thu, 11 Mar 2021 21:54:00 -0500 Subject: [PATCH 3/3] better derivation path building --- src/wallet/signer.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/wallet/signer.rs b/src/wallet/signer.rs index 3ff02425..16f9af30 100644 --- a/src/wallet/signer.rs +++ b/src/wallet/signer.rs @@ -225,18 +225,8 @@ impl Signer for DescriptorXKey { let derived_key = match self.origin.clone() { Some((_fingerprint, origin_path)) => { let deriv_path = DerivationPath::from( - full_path - .into_iter() - .enumerate() - .filter_map(|(i, child)| { - if i >= origin_path.len() { - Some(child) - } else { - None - } - }) - .cloned() - .collect::>(), + &full_path.into_iter().cloned().collect::>() + [origin_path.len()..], ); self.xkey.derive_priv(&secp, &deriv_path).unwrap() }