use bitcoin::secp256k1::{Secp256k1, Verification};
use bitcoin::{Network, Script};
#[cfg(feature = "miniscript")]
use bitcoin_hd::{DerivationAccount, DerivePatternError};
use bitcoin_hd::{DeriveError, UnhardenedIndex};
use bitcoin_scripts::address::AddressCompat;
#[cfg(not(feature = "miniscript"))]
pub mod miniscript {
#[derive(
Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error
)]
#[display(Debug)]
pub enum Error {}
}
pub trait DeriveDescriptor<Key> {
type Output;
fn derive_descriptor<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<Self::Output, DeriveError>;
}
pub trait Descriptor<Key> {
fn check_sanity(&self) -> Result<(), DeriveError>;
fn derive_pattern_len(&self) -> Result<usize, DeriveError>;
fn network(&self, regtest: bool) -> Result<Network, DeriveError>;
fn address<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
regtest: bool,
) -> Result<AddressCompat, DeriveError>;
fn script_pubkey_pretr<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<Script, DeriveError>;
fn script_pubkey_tr<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<Script, DeriveError>;
}
#[cfg(feature = "miniscript")]
mod ms {
use std::cell::Cell;
use bitcoin::XOnlyPublicKey;
use bitcoin_hd::account::DerivePublicKey;
use bitcoin_hd::SegmentIndexes;
use bitcoin_scripts::address::AddressNetwork;
use miniscript::{translate_hash_fail, ForEachKey, TranslatePk, Translator};
use super::*;
struct KeyTranslator<'a, C: Verification> {
secp: &'a Secp256k1<C>,
pat: &'a [UnhardenedIndex],
}
impl<'a, C> Translator<DerivationAccount, bitcoin::PublicKey, DerivePatternError>
for KeyTranslator<'a, C>
where
C: Verification,
{
fn pk(&mut self, pk: &DerivationAccount) -> Result<bitcoin::PublicKey, DerivePatternError> {
pk.derive_public_key(self.secp, self.pat)
.map(bitcoin::PublicKey::new)
}
translate_hash_fail!(DerivationAccount, bitcoin::PublicKey, DerivePatternError);
}
impl<'a, C> Translator<DerivationAccount, XOnlyPublicKey, DerivePatternError>
for KeyTranslator<'a, C>
where
C: Verification,
{
fn pk(&mut self, pk: &DerivationAccount) -> Result<XOnlyPublicKey, DerivePatternError> {
pk.derive_public_key(self.secp, self.pat)
.map(XOnlyPublicKey::from)
}
translate_hash_fail!(DerivationAccount, XOnlyPublicKey, DerivePatternError);
}
impl DeriveDescriptor<bitcoin::PublicKey> for miniscript::Descriptor<DerivationAccount>
where
Self: TranslatePk<DerivationAccount, bitcoin::PublicKey>,
{
type Output = miniscript::Descriptor<bitcoin::PublicKey>;
fn derive_descriptor<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<miniscript::Descriptor<bitcoin::PublicKey>, DeriveError> {
let pat = pat.as_ref();
if pat.len() != self.derive_pattern_len()? {
return Err(DeriveError::DerivePatternMismatch);
}
let mut translator = KeyTranslator { secp, pat };
<miniscript::Descriptor<DerivationAccount> as TranslatePk<_, bitcoin::PublicKey>>::translate_pk(self, &mut translator)
.map_err(DeriveError::from)
}
}
impl DeriveDescriptor<XOnlyPublicKey> for miniscript::Descriptor<DerivationAccount>
where
Self: TranslatePk<DerivationAccount, XOnlyPublicKey>,
{
type Output = miniscript::Descriptor<XOnlyPublicKey>;
fn derive_descriptor<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<miniscript::Descriptor<XOnlyPublicKey>, DeriveError> {
let pat = pat.as_ref();
if pat.len() != self.derive_pattern_len()? {
return Err(DeriveError::DerivePatternMismatch);
}
let mut translator = KeyTranslator { secp, pat };
<miniscript::Descriptor<DerivationAccount> as TranslatePk<_, XOnlyPublicKey>>::translate_pk(self, &mut translator)
.map_err(DeriveError::from)
}
}
impl Descriptor<DerivationAccount> for miniscript::Descriptor<DerivationAccount> {
#[inline]
fn check_sanity(&self) -> Result<(), DeriveError> {
self.derive_pattern_len()?;
self.network(false)?;
Ok(())
}
fn derive_pattern_len(&self) -> Result<usize, DeriveError> {
let len = Cell::new(None);
self.for_each_key(|key| {
let c = key
.terminal_path
.iter()
.filter(|step| step.count() > 1)
.count();
match (len.get(), c) {
(None, c) => {
len.set(Some(c));
true
}
(Some(c1), c2) if c1 != c2 => false,
_ => true,
}
});
len.get().ok_or(DeriveError::NoKeys)
}
fn network(&self, regtest: bool) -> Result<Network, DeriveError> {
let network = Cell::new(None);
self.for_each_key(|key| match (network.get(), key.account_xpub.network) {
(None, net) => {
network.set(Some(net));
true
}
(Some(net1), net2) if net1 != net2 => false,
_ => true,
});
let network = network.get().ok_or(DeriveError::NoKeys)?;
match (network, regtest) {
(network, false) => Ok(network),
(Network::Testnet | Network::Signet | Network::Regtest, true) if regtest => {
Ok(Network::Regtest)
}
_ => Err(DeriveError::InconsistentKeyNetwork),
}
}
#[inline]
fn address<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
regtest: bool,
) -> Result<AddressCompat, DeriveError> {
let network = AddressNetwork::from(self.network(regtest)?);
let spk = Descriptor::script_pubkey_pretr(self, secp, pat)?;
AddressCompat::from_script(&spk.into(), network)
.ok_or(DeriveError::NoAddressForDescriptor)
}
#[inline]
fn script_pubkey_pretr<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<Script, DeriveError> {
let d =
<Self as DeriveDescriptor<bitcoin::PublicKey>>::derive_descriptor(self, secp, pat)?;
Ok(d.script_pubkey())
}
#[inline]
fn script_pubkey_tr<C: Verification>(
&self,
secp: &Secp256k1<C>,
pat: impl AsRef<[UnhardenedIndex]>,
) -> Result<Script, DeriveError> {
let d = <Self as DeriveDescriptor<XOnlyPublicKey>>::derive_descriptor(self, secp, pat)?;
Ok(d.script_pubkey())
}
}
}