Attach a context to our software signers
This allows the signer to know the signing context precisely without relying on heuristics on the psbt fields. Due to the context being static, we still have to look at the PSBT when producing taproot signatures to determine the set of leaf hashes that the key can sign for.
This commit is contained in:
parent
906598ad92
commit
1312184ed7
@ -21,6 +21,7 @@
|
|||||||
//! ```
|
//! ```
|
||||||
//! # use std::sync::Arc;
|
//! # use std::sync::Arc;
|
||||||
//! # use bdk::descriptor::*;
|
//! # use bdk::descriptor::*;
|
||||||
|
//! # use bdk::wallet::signer::*;
|
||||||
//! # use bdk::bitcoin::secp256k1::Secp256k1;
|
//! # use bdk::bitcoin::secp256k1::Secp256k1;
|
||||||
//! use bdk::descriptor::policy::BuildSatisfaction;
|
//! use bdk::descriptor::policy::BuildSatisfaction;
|
||||||
//! let secp = Secp256k1::new();
|
//! let secp = Secp256k1::new();
|
||||||
@ -29,7 +30,7 @@
|
|||||||
//! let (extended_desc, key_map) = ExtendedDescriptor::parse_descriptor(&secp, desc)?;
|
//! let (extended_desc, key_map) = ExtendedDescriptor::parse_descriptor(&secp, desc)?;
|
||||||
//! println!("{:?}", extended_desc);
|
//! println!("{:?}", extended_desc);
|
||||||
//!
|
//!
|
||||||
//! let signers = Arc::new(key_map.into());
|
//! let signers = Arc::new(SignersContainer::build(key_map, &extended_desc, &secp));
|
||||||
//! let policy = extended_desc.extract_policy(&signers, BuildSatisfaction::None, &secp)?;
|
//! let policy = extended_desc.extract_policy(&signers, BuildSatisfaction::None, &secp)?;
|
||||||
//! println!("policy: {}", serde_json::to_string(&policy)?);
|
//! println!("policy: {}", serde_json::to_string(&policy)?);
|
||||||
//! # Ok::<(), bdk::Error>(())
|
//! # Ok::<(), bdk::Error>(())
|
||||||
@ -1109,7 +1110,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1124,7 +1125,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1148,7 +1149,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1180,7 +1181,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1212,7 +1213,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1244,7 +1245,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1277,7 +1278,7 @@ mod test {
|
|||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let single_key = wallet_desc.derive(0);
|
let single_key = wallet_desc.derive(0);
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = single_key
|
let policy = single_key
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1293,7 +1294,7 @@ mod test {
|
|||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let single_key = wallet_desc.derive(0);
|
let single_key = wallet_desc.derive(0);
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = single_key
|
let policy = single_key
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1320,7 +1321,7 @@ mod test {
|
|||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let single_key = wallet_desc.derive(0);
|
let single_key = wallet_desc.derive(0);
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = single_key
|
let policy = single_key
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1363,7 +1364,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1402,7 +1403,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1427,7 +1428,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1445,7 +1446,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1467,10 +1468,10 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers = keymap.into();
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
|
|
||||||
let policy = wallet_desc
|
let policy = wallet_desc
|
||||||
.extract_policy(&signers, BuildSatisfaction::None, &secp)
|
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -1533,7 +1534,7 @@ mod test {
|
|||||||
addr.to_string()
|
addr.to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
|
|
||||||
let psbt = Psbt::from_str(ALICE_SIGNED_PSBT).unwrap();
|
let psbt = Psbt::from_str(ALICE_SIGNED_PSBT).unwrap();
|
||||||
|
|
||||||
@ -1594,7 +1595,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
|
|
||||||
let addr = wallet_desc
|
let addr = wallet_desc
|
||||||
.as_derived(0, &secp)
|
.as_derived(0, &secp)
|
||||||
@ -1682,7 +1683,7 @@ mod test {
|
|||||||
let (wallet_desc, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers_container = Arc::new(SignersContainer::from(keymap));
|
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
|
||||||
|
|
||||||
let policy = wallet_desc.extract_policy(&signers_container, BuildSatisfaction::None, &secp);
|
let policy = wallet_desc.extract_policy(&signers_container, BuildSatisfaction::None, &secp);
|
||||||
assert!(policy.is_ok());
|
assert!(policy.is_ok());
|
||||||
|
@ -197,7 +197,7 @@ where
|
|||||||
KeychainKind::External,
|
KeychainKind::External,
|
||||||
get_checksum(&descriptor.to_string())?.as_bytes(),
|
get_checksum(&descriptor.to_string())?.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
let signers = Arc::new(SignersContainer::from(keymap));
|
let signers = Arc::new(SignersContainer::build(keymap, &descriptor, &secp));
|
||||||
let (change_descriptor, change_signers) = match change_descriptor {
|
let (change_descriptor, change_signers) = match change_descriptor {
|
||||||
Some(desc) => {
|
Some(desc) => {
|
||||||
let (change_descriptor, change_keymap) =
|
let (change_descriptor, change_keymap) =
|
||||||
@ -207,7 +207,11 @@ where
|
|||||||
get_checksum(&change_descriptor.to_string())?.as_bytes(),
|
get_checksum(&change_descriptor.to_string())?.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let change_signers = Arc::new(SignersContainer::from(change_keymap));
|
let change_signers = Arc::new(SignersContainer::build(
|
||||||
|
change_keymap,
|
||||||
|
&change_descriptor,
|
||||||
|
&secp,
|
||||||
|
));
|
||||||
// if !parsed.same_structure(descriptor.as_ref()) {
|
// if !parsed.same_structure(descriptor.as_ref()) {
|
||||||
// return Err(Error::DifferentDescriptorStructure);
|
// return Err(Error::DifferentDescriptorStructure);
|
||||||
// }
|
// }
|
||||||
|
@ -82,23 +82,26 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Bound::Included;
|
use std::ops::{Bound::Included, Deref};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use bitcoin::blockdata::opcodes;
|
use bitcoin::blockdata::opcodes;
|
||||||
use bitcoin::blockdata::script::Builder as ScriptBuilder;
|
use bitcoin::blockdata::script::Builder as ScriptBuilder;
|
||||||
use bitcoin::hashes::{hash160, Hash};
|
use bitcoin::hashes::{hash160, Hash};
|
||||||
use bitcoin::secp256k1::{Message, Secp256k1};
|
use bitcoin::secp256k1::Message;
|
||||||
use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint};
|
use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint};
|
||||||
use bitcoin::util::{ecdsa, psbt, schnorr, sighash, taproot};
|
use bitcoin::util::{ecdsa, psbt, schnorr, sighash, taproot};
|
||||||
use bitcoin::{secp256k1, XOnlyPublicKey};
|
use bitcoin::{secp256k1, XOnlyPublicKey};
|
||||||
use bitcoin::{EcdsaSighashType, PrivateKey, PublicKey, SchnorrSighashType, Script};
|
use bitcoin::{EcdsaSighashType, PrivateKey, PublicKey, SchnorrSighashType, Script};
|
||||||
|
|
||||||
use miniscript::descriptor::{DescriptorSecretKey, DescriptorSinglePriv, DescriptorXKey, KeyMap};
|
use miniscript::descriptor::{
|
||||||
|
Descriptor, DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorXKey,
|
||||||
|
KeyMap,
|
||||||
|
};
|
||||||
use miniscript::{Legacy, MiniscriptKey, Segwitv0, Tap};
|
use miniscript::{Legacy, MiniscriptKey, Segwitv0, Tap};
|
||||||
|
|
||||||
use super::utils::SecpCtx;
|
use super::utils::SecpCtx;
|
||||||
use crate::descriptor::XKeyUtils;
|
use crate::descriptor::{DescriptorMeta, XKeyUtils};
|
||||||
|
|
||||||
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
|
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
|
||||||
/// multiple of them
|
/// multiple of them
|
||||||
@ -171,6 +174,44 @@ impl fmt::Display for SignerError {
|
|||||||
|
|
||||||
impl std::error::Error for SignerError {}
|
impl std::error::Error for SignerError {}
|
||||||
|
|
||||||
|
/// Signing context
|
||||||
|
///
|
||||||
|
/// Used by our software signers to determine the type of signatures to make
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum SignerContext {
|
||||||
|
/// Legacy context
|
||||||
|
Legacy,
|
||||||
|
/// Segwit v0 context (BIP 143)
|
||||||
|
Segwitv0,
|
||||||
|
/// Taproot context (BIP 340)
|
||||||
|
Tap {
|
||||||
|
/// Whether the signer can sign for the internal key or not
|
||||||
|
is_internal_key: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper structure to pair a signer with its context
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SignerWrapper<S: Sized + fmt::Debug + Clone> {
|
||||||
|
signer: S,
|
||||||
|
ctx: SignerContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Sized + fmt::Debug + Clone> SignerWrapper<S> {
|
||||||
|
/// Create a wrapped signer from a signer and a context
|
||||||
|
pub fn new(signer: S, ctx: SignerContext) -> Self {
|
||||||
|
SignerWrapper { signer, ctx }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Sized + fmt::Debug + Clone> Deref for SignerWrapper<S> {
|
||||||
|
type Target = S;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.signer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Common signer methods
|
/// Common signer methods
|
||||||
pub trait SignerCommon: fmt::Debug + Send + Sync {
|
pub trait SignerCommon: fmt::Debug + Send + Sync {
|
||||||
/// Return the [`SignerId`] for this signer
|
/// Return the [`SignerId`] for this signer
|
||||||
@ -231,17 +272,17 @@ impl<T: InputSigner> TransactionSigner for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignerCommon for DescriptorXKey<ExtendedPrivKey> {
|
impl SignerCommon for SignerWrapper<DescriptorXKey<ExtendedPrivKey>> {
|
||||||
fn id(&self, secp: &SecpCtx) -> SignerId {
|
fn id(&self, secp: &SecpCtx) -> SignerId {
|
||||||
SignerId::from(self.root_fingerprint(secp))
|
SignerId::from(self.root_fingerprint(secp))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
|
fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
|
||||||
Some(DescriptorSecretKey::XPrv(self.clone()))
|
Some(DescriptorSecretKey::XPrv(self.signer.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputSigner for DescriptorXKey<ExtendedPrivKey> {
|
impl InputSigner for SignerWrapper<DescriptorXKey<ExtendedPrivKey>> {
|
||||||
fn sign_input(
|
fn sign_input(
|
||||||
&self,
|
&self,
|
||||||
psbt: &mut psbt::PartiallySignedTransaction,
|
psbt: &mut psbt::PartiallySignedTransaction,
|
||||||
@ -289,30 +330,31 @@ impl InputSigner for DescriptorXKey<ExtendedPrivKey> {
|
|||||||
Err(SignerError::InvalidKey)
|
Err(SignerError::InvalidKey)
|
||||||
} else {
|
} else {
|
||||||
// HD wallets imply compressed keys
|
// HD wallets imply compressed keys
|
||||||
PrivateKey {
|
let priv_key = PrivateKey {
|
||||||
compressed: true,
|
compressed: true,
|
||||||
network: self.xkey.network,
|
network: self.xkey.network,
|
||||||
inner: derived_key.private_key,
|
inner: derived_key.private_key,
|
||||||
}
|
};
|
||||||
.sign_input(psbt, input_index, secp)
|
|
||||||
|
SignerWrapper::new(priv_key, self.ctx).sign_input(psbt, input_index, secp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignerCommon for PrivateKey {
|
impl SignerCommon for SignerWrapper<PrivateKey> {
|
||||||
fn id(&self, secp: &SecpCtx) -> SignerId {
|
fn id(&self, secp: &SecpCtx) -> SignerId {
|
||||||
SignerId::from(self.public_key(secp).to_pubkeyhash())
|
SignerId::from(self.public_key(secp).to_pubkeyhash())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
|
fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
|
||||||
Some(DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
|
Some(DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
|
||||||
key: *self,
|
key: self.signer,
|
||||||
origin: None,
|
origin: None,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputSigner for PrivateKey {
|
impl InputSigner for SignerWrapper<PrivateKey> {
|
||||||
fn sign_input(
|
fn sign_input(
|
||||||
&self,
|
&self,
|
||||||
psbt: &mut psbt::PartiallySignedTransaction,
|
psbt: &mut psbt::PartiallySignedTransaction,
|
||||||
@ -331,11 +373,9 @@ impl InputSigner for PrivateKey {
|
|||||||
|
|
||||||
let pubkey = PublicKey::from_private_key(secp, self);
|
let pubkey = PublicKey::from_private_key(secp, self);
|
||||||
let x_only_pubkey = XOnlyPublicKey::from(pubkey.inner);
|
let x_only_pubkey = XOnlyPublicKey::from(pubkey.inner);
|
||||||
let is_taproot = psbt.inputs[input_index].tap_internal_key.is_some()
|
|
||||||
|| psbt.inputs[input_index].tap_merkle_root.is_some();
|
|
||||||
|
|
||||||
match psbt.inputs[input_index].tap_internal_key {
|
if let SignerContext::Tap { is_internal_key } = self.ctx {
|
||||||
Some(k) if k == x_only_pubkey && psbt.inputs[input_index].tap_key_sig.is_none() => {
|
if is_internal_key && psbt.inputs[input_index].tap_key_sig.is_none() {
|
||||||
let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
|
let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
|
||||||
sign_psbt_schnorr(
|
sign_psbt_schnorr(
|
||||||
&self.inner,
|
&self.inner,
|
||||||
@ -347,56 +387,54 @@ impl InputSigner for PrivateKey {
|
|||||||
secp,
|
secp,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
if let Some((leaf_hashes, _)) = psbt.inputs[input_index].tap_key_origins.get(&x_only_pubkey)
|
|
||||||
{
|
|
||||||
let leaf_hashes = leaf_hashes
|
|
||||||
.iter()
|
|
||||||
.filter(|lh| {
|
|
||||||
!psbt.inputs[input_index]
|
|
||||||
.tap_script_sigs
|
|
||||||
.contains_key(&(x_only_pubkey, **lh))
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for lh in leaf_hashes {
|
|
||||||
let (hash, hash_ty) = Tap::sighash(psbt, input_index, Some(lh))?;
|
|
||||||
sign_psbt_schnorr(
|
|
||||||
&self.inner,
|
|
||||||
x_only_pubkey,
|
|
||||||
Some(lh),
|
|
||||||
&mut psbt.inputs[input_index],
|
|
||||||
hash,
|
|
||||||
hash_ty,
|
|
||||||
secp,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !is_taproot {
|
if let Some((leaf_hashes, _)) =
|
||||||
if psbt.inputs[input_index].partial_sigs.contains_key(&pubkey) {
|
psbt.inputs[input_index].tap_key_origins.get(&x_only_pubkey)
|
||||||
return Ok(());
|
{
|
||||||
|
let leaf_hashes = leaf_hashes
|
||||||
|
.iter()
|
||||||
|
.filter(|lh| {
|
||||||
|
!psbt.inputs[input_index]
|
||||||
|
.tap_script_sigs
|
||||||
|
.contains_key(&(x_only_pubkey, **lh))
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for lh in leaf_hashes {
|
||||||
|
let (hash, hash_ty) = Tap::sighash(psbt, input_index, Some(lh))?;
|
||||||
|
sign_psbt_schnorr(
|
||||||
|
&self.inner,
|
||||||
|
x_only_pubkey,
|
||||||
|
Some(lh),
|
||||||
|
&mut psbt.inputs[input_index],
|
||||||
|
hash,
|
||||||
|
hash_ty,
|
||||||
|
secp,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: use the presence of `witness_utxo` as an indication that we should make a bip143
|
return Ok(());
|
||||||
// sig. Does this make sense? Should we add an extra argument to explicitly switch between
|
|
||||||
// these? The original idea was to declare sign() as sign<Ctx: ScriptContex>() and use Ctx,
|
|
||||||
// but that violates the rules for trait-objects, so we can't do it.
|
|
||||||
let (hash, hash_ty) = match psbt.inputs[input_index].witness_utxo {
|
|
||||||
Some(_) => Segwitv0::sighash(psbt, input_index, ())?,
|
|
||||||
None => Legacy::sighash(psbt, input_index, ())?,
|
|
||||||
};
|
|
||||||
sign_psbt_ecdsa(
|
|
||||||
&self.inner,
|
|
||||||
pubkey,
|
|
||||||
&mut psbt.inputs[input_index],
|
|
||||||
hash,
|
|
||||||
hash_ty,
|
|
||||||
secp,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if psbt.inputs[input_index].partial_sigs.contains_key(&pubkey) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (hash, hash_ty) = match self.ctx {
|
||||||
|
SignerContext::Segwitv0 => Segwitv0::sighash(psbt, input_index, ())?,
|
||||||
|
SignerContext::Legacy => Legacy::sighash(psbt, input_index, ())?,
|
||||||
|
_ => return Ok(()), // handled above
|
||||||
|
};
|
||||||
|
sign_psbt_ecdsa(
|
||||||
|
&self.inner,
|
||||||
|
pubkey,
|
||||||
|
&mut psbt.inputs[input_index],
|
||||||
|
hash,
|
||||||
|
hash_ty,
|
||||||
|
secp,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -496,24 +534,37 @@ impl SignersContainer {
|
|||||||
.filter_map(|secret| secret.as_public(secp).ok().map(|public| (public, secret)))
|
.filter_map(|secret| secret.as_public(secp).ok().map(|public| (public, secret)))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<KeyMap> for SignersContainer {
|
/// Build a new signer container from a [`KeyMap`]
|
||||||
fn from(keymap: KeyMap) -> SignersContainer {
|
///
|
||||||
let secp = Secp256k1::new();
|
/// Also looks at the corresponding descriptor to determine the [`SignerContext`] to attach to
|
||||||
|
/// the signers
|
||||||
|
pub fn build(
|
||||||
|
keymap: KeyMap,
|
||||||
|
descriptor: &Descriptor<DescriptorPublicKey>,
|
||||||
|
secp: &SecpCtx,
|
||||||
|
) -> SignersContainer {
|
||||||
let mut container = SignersContainer::new();
|
let mut container = SignersContainer::new();
|
||||||
|
|
||||||
for (_, secret) in keymap {
|
for (pubkey, secret) in keymap {
|
||||||
|
let ctx = match descriptor {
|
||||||
|
Descriptor::Tr(tr) => SignerContext::Tap {
|
||||||
|
is_internal_key: tr.internal_key() == &pubkey,
|
||||||
|
},
|
||||||
|
_ if descriptor.is_witness() => SignerContext::Segwitv0,
|
||||||
|
_ => SignerContext::Legacy,
|
||||||
|
};
|
||||||
|
|
||||||
match secret {
|
match secret {
|
||||||
DescriptorSecretKey::SinglePriv(private_key) => container.add_external(
|
DescriptorSecretKey::SinglePriv(private_key) => container.add_external(
|
||||||
SignerId::from(private_key.key.public_key(&secp).to_pubkeyhash()),
|
SignerId::from(private_key.key.public_key(secp).to_pubkeyhash()),
|
||||||
SignerOrdering::default(),
|
SignerOrdering::default(),
|
||||||
Arc::new(private_key.key),
|
Arc::new(SignerWrapper::new(private_key.key, ctx)),
|
||||||
),
|
),
|
||||||
DescriptorSecretKey::XPrv(xprv) => container.add_external(
|
DescriptorSecretKey::XPrv(xprv) => container.add_external(
|
||||||
SignerId::from(xprv.root_fingerprint(&secp)),
|
SignerId::from(xprv.root_fingerprint(secp)),
|
||||||
SignerOrdering::default(),
|
SignerOrdering::default(),
|
||||||
Arc::new(xprv),
|
Arc::new(SignerWrapper::new(xprv, ctx)),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -869,11 +920,11 @@ mod signers_container_tests {
|
|||||||
let (prvkey1, _, _) = setup_keys(TPRV0_STR);
|
let (prvkey1, _, _) = setup_keys(TPRV0_STR);
|
||||||
let (prvkey2, _, _) = setup_keys(TPRV1_STR);
|
let (prvkey2, _, _) = setup_keys(TPRV1_STR);
|
||||||
let desc = descriptor!(sh(multi(2, prvkey1, prvkey2))).unwrap();
|
let desc = descriptor!(sh(multi(2, prvkey1, prvkey2))).unwrap();
|
||||||
let (_, keymap) = desc
|
let (wallet_desc, keymap) = desc
|
||||||
.into_wallet_descriptor(&secp, Network::Testnet)
|
.into_wallet_descriptor(&secp, Network::Testnet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let signers = SignersContainer::from(keymap);
|
let signers = SignersContainer::build(keymap, &wallet_desc, &secp);
|
||||||
assert_eq!(signers.ids().len(), 2);
|
assert_eq!(signers.ids().len(), 2);
|
||||||
|
|
||||||
let signers = signers.signers();
|
let signers = signers.signers();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user