]> Untitled Git - bdk/commitdiff
Create a PSBT signer from an ExtendedDescriptor
authorAlekos Filini <alekos.filini@gmail.com>
Tue, 4 Feb 2020 10:05:54 +0000 (11:05 +0100)
committerAlekos Filini <alekos.filini@gmail.com>
Fri, 7 Feb 2020 10:48:01 +0000 (11:48 +0100)
core/lib/Cargo.toml
core/lib/examples/psbt.rs [new file with mode: 0644]
core/lib/src/descriptor/mod.rs
core/lib/src/lib.rs

index d9b119a02e64888d4bec1a989a3855743fd77f7c..6894d5e981cf6e4203f705cda7ac83022df48e57 100644 (file)
@@ -9,3 +9,4 @@ bitcoin = { version = "0.23", features = ["use-serde"] }
 miniscript = { version = "0.12" }
 serde = { version = "^1.0", features = ["derive"] }
 serde_json = { version = "^1.0" }
+base64 = "^0.11"
diff --git a/core/lib/examples/psbt.rs b/core/lib/examples/psbt.rs
new file mode 100644 (file)
index 0000000..ed0281f
--- /dev/null
@@ -0,0 +1,50 @@
+extern crate base64;
+extern crate magical_bitcoin_wallet;
+
+use std::str::FromStr;
+
+use magical_bitcoin_wallet::bitcoin;
+use magical_bitcoin_wallet::descriptor::*;
+use magical_bitcoin_wallet::psbt::*;
+use magical_bitcoin_wallet::signer::Signer;
+
+use bitcoin::consensus::encode::{deserialize, serialize};
+use bitcoin::util::psbt::PartiallySignedTransaction;
+use bitcoin::SigHashType;
+
+fn main() {
+    let desc = "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/*)";
+
+    let extended_desc = ExtendedDescriptor::from_str(desc).unwrap();
+
+    let psbt_str = "cHNidP8BAFMCAAAAAd9SiQfxXZ+CKjgjRNonWXsnlA84aLvjxtwCmMfRc0ZbAQAAAAD+////ASjS9QUAAAAAF6kUYJR3oB0lS1M0W1RRMMiENSX45IuHAAAAAAABAPUCAAAAA9I7/OqeFeOFdr5VTLnj3UI/CNRw2eWmMPf7qDv6uIF6AAAAABcWABTG+kgr0g44V0sK9/9FN9oG/CxMK/7///+d0ffphPcV6FE9J/3ZPKWu17YxBnWWTJQyRJs3HUo1gwEAAAAA/v///835mYd9DmnjVnUKd2421MDoZmIxvB4XyJluN3SPUV9hAAAAABcWABRfvwFGp+x/yWdXeNgFs9v0duyeS/7///8CFbH+AAAAAAAXqRSEnTOAjJN/X6ZgR9ftKmwisNSZx4cA4fUFAAAAABl2qRTs6pS4x17MSQ4yNs/1GPsfdlv2NIisAAAAACIGApVE9PPtkcqp8Da43yrXGv4nLOotZdyxwJoTWQxuLxIuCAxfmh4JAAAAAAA=";
+    let psbt_buf = base64::decode(psbt_str).unwrap();
+    let mut psbt: PartiallySignedTransaction = deserialize(&psbt_buf).unwrap();
+
+    let signer = PSBTSigner::from_descriptor(&psbt.global.unsigned_tx, &extended_desc).unwrap();
+
+    for (index, input) in psbt.inputs.iter_mut().enumerate() {
+        for (pubkey, (fing, path)) in &input.hd_keypaths {
+            let sighash = input.sighash_type.unwrap_or(SigHashType::All);
+
+            // Ignore the "witness_utxo" case because we know this psbt is a legacy tx
+            if let Some(non_wit_utxo) = &input.non_witness_utxo {
+                let prev_script = &non_wit_utxo.output
+                    [psbt.global.unsigned_tx.input[index].previous_output.vout as usize]
+                    .script_pubkey;
+                let (signature, sighash) = signer
+                    .sig_legacy_from_fingerprint(index, sighash, fing, path, prev_script)
+                    .unwrap()
+                    .unwrap();
+
+                let mut concat_sig = Vec::new();
+                concat_sig.extend_from_slice(&signature.serialize_der());
+                concat_sig.extend_from_slice(&[sighash as u8]);
+
+                input.partial_sigs.insert(*pubkey, concat_sig);
+            }
+        }
+    }
+
+    println!("signed: {}", base64::encode(&serialize(&psbt)));
+}
index d3cb14fe80d259f79fb815fa654ab6353f46e463..01c6a0a8f5976e10123e7173c2f2cb40acec5774 100644 (file)
@@ -94,11 +94,7 @@ where
 trait Key: std::fmt::Debug {
     fn fingerprint(&self, secp: &Secp256k1<All>) -> Option<Fingerprint>;
     fn as_public_key(&self, secp: &Secp256k1<All>, index: Option<u32>) -> Result<PublicKey, Error>;
-    fn as_secret_key(
-        &self,
-        secp: &Secp256k1<All>,
-        index: Option<u32>,
-    ) -> Result<Option<PrivateKey>, Error>;
+    fn as_secret_key(&self) -> Option<PrivateKey>;
     fn xprv(&self) -> Option<ExtendedPrivKey>;
     fn full_path(&self, index: u32) -> Option<DerivationPath>;
     fn is_fixed(&self) -> bool;
@@ -117,12 +113,8 @@ impl Key for PublicKey {
         Ok(PublicKey::clone(self))
     }
 
-    fn as_secret_key(
-        &self,
-        _secp: &Secp256k1<All>,
-        _index: Option<u32>,
-    ) -> Result<Option<PrivateKey>, Error> {
-        Ok(None)
+    fn as_secret_key(&self) -> Option<PrivateKey> {
+        None
     }
 
     fn xprv(&self) -> Option<ExtendedPrivKey> {
@@ -151,12 +143,8 @@ impl Key for PrivateKey {
         Ok(self.public_key(secp))
     }
 
-    fn as_secret_key(
-        &self,
-        _secp: &Secp256k1<All>,
-        _index: Option<u32>,
-    ) -> Result<Option<PrivateKey>, Error> {
-        Ok(Some(PrivateKey::clone(self)))
+    fn as_secret_key(&self) -> Option<PrivateKey> {
+        Some(PrivateKey::clone(self))
     }
 
     fn xprv(&self) -> Option<ExtendedPrivKey> {
@@ -181,22 +169,8 @@ impl Key for DescriptorExtendedKey {
         Ok(self.derive_xpub(secp, index.unwrap_or(0))?.public_key)
     }
 
-    fn as_secret_key(
-        &self,
-        secp: &Secp256k1<All>,
-        index: Option<u32>,
-    ) -> Result<Option<PrivateKey>, Error> {
-        if self.secret.is_none() {
-            return Ok(None);
-        }
-
-        let derivation_path = self.full_path(index.unwrap_or(0));
-        Ok(Some(
-            self.secret
-                .unwrap()
-                .derive_priv(secp, &derivation_path)?
-                .private_key,
-        ))
+    fn as_secret_key(&self) -> Option<PrivateKey> {
+        None
     }
 
     fn xprv(&self) -> Option<ExtendedPrivKey> {
@@ -295,6 +269,14 @@ impl ExtendedDescriptor {
             .collect()
     }
 
+    pub fn get_secret_keys(&self) -> Vec<PrivateKey> {
+        self.keys
+            .iter()
+            .filter(|(_, v)| v.as_secret_key().is_some())
+            .map(|(_, v)| v.as_secret_key().unwrap())
+            .collect()
+    }
+
     pub fn get_hd_keypaths(
         &self,
         index: u32,
index 16d34ebe35012aa5f786231602278cde24552b0e..242393c99711199f12de227642b5f69ad3ded38e 100644 (file)
@@ -4,5 +4,8 @@ pub extern crate miniscript;
 extern crate serde;
 extern crate serde_json;
 
-pub mod descriptor;
+#[macro_use]
 pub mod error;
+pub mod descriptor;
+pub mod psbt;
+pub mod signer;