bdk_wallet/keys/
mod.rs

1// Bitcoin Dev Kit
2// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3//
4// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5//
6// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9// You may not use this file except in accordance with one or both of these
10// licenses.
11
12//! Key formats
13
14use crate::collections::HashSet;
15use alloc::string::{String, ToString};
16use alloc::vec::Vec;
17use core::any::TypeId;
18use core::fmt;
19use core::marker::PhantomData;
20use core::ops::Deref;
21use core::str::FromStr;
22
23use rand_core::{CryptoRng, RngCore};
24
25use bitcoin::secp256k1::{self, Secp256k1, Signing};
26
27use bitcoin::bip32;
28use bitcoin::{key::XOnlyPublicKey, Network, PrivateKey, PublicKey};
29
30use miniscript::descriptor::{Descriptor, DescriptorMultiXKey, DescriptorXKey, Wildcard};
31pub use miniscript::descriptor::{
32    DescriptorPublicKey, DescriptorSecretKey, KeyMap, SinglePriv, SinglePub, SinglePubKey,
33    SortedMultiVec,
34};
35pub use miniscript::ScriptContext;
36use miniscript::{Miniscript, Terminal};
37
38use crate::descriptor::{CheckMiniscript, DescriptorError};
39use crate::wallet::utils::SecpCtx;
40
41#[cfg(feature = "keys-bip39")]
42#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
43pub mod bip39;
44
45/// Set of valid networks for a key
46pub type ValidNetworks = HashSet<Network>;
47
48/// Create a set containing mainnet, testnet, testnet4, signet, and regtest
49pub fn any_network() -> ValidNetworks {
50    vec![
51        Network::Bitcoin,
52        Network::Testnet,
53        Network::Testnet4,
54        Network::Regtest,
55        Network::Signet,
56    ]
57    .into_iter()
58    .collect()
59}
60/// Create a set only containing mainnet
61pub fn mainnet_network() -> ValidNetworks {
62    vec![Network::Bitcoin].into_iter().collect()
63}
64/// Create a set containing test networks
65pub fn test_networks() -> ValidNetworks {
66    vec![
67        Network::Testnet,
68        Network::Testnet4,
69        Network::Regtest,
70        Network::Signet,
71    ]
72    .into_iter()
73    .collect()
74}
75/// Compute the intersection of two sets
76pub fn merge_networks(a: &ValidNetworks, b: &ValidNetworks) -> ValidNetworks {
77    a.intersection(b).cloned().collect()
78}
79
80/// Container for public or secret keys
81#[derive(Debug)]
82pub enum DescriptorKey<Ctx: ScriptContext> {
83    #[doc(hidden)]
84    Public(DescriptorPublicKey, ValidNetworks, PhantomData<Ctx>),
85    #[doc(hidden)]
86    Secret(DescriptorSecretKey, ValidNetworks, PhantomData<Ctx>),
87}
88
89impl<Ctx: ScriptContext> DescriptorKey<Ctx> {
90    /// Create an instance given a public key and a set of valid networks
91    pub fn from_public(public: DescriptorPublicKey, networks: ValidNetworks) -> Self {
92        DescriptorKey::Public(public, networks, PhantomData)
93    }
94
95    /// Create an instance given a secret key and a set of valid networks
96    pub fn from_secret(secret: DescriptorSecretKey, networks: ValidNetworks) -> Self {
97        DescriptorKey::Secret(secret, networks, PhantomData)
98    }
99
100    /// Override the computed set of valid networks
101    pub fn override_valid_networks(self, networks: ValidNetworks) -> Self {
102        match self {
103            DescriptorKey::Public(key, _, _) => DescriptorKey::Public(key, networks, PhantomData),
104            DescriptorKey::Secret(key, _, _) => DescriptorKey::Secret(key, networks, PhantomData),
105        }
106    }
107
108    // This method is used internally by `bdk_wallet::fragment!` and `bdk_wallet::descriptor!`. It
109    // has to be public because it is effectively called by external crates once the macros are
110    // expanded, but since it is not meant to be part of the public api we hide it from the
111    // docs.
112    #[doc(hidden)]
113    pub fn extract(
114        self,
115        secp: &SecpCtx,
116    ) -> Result<(DescriptorPublicKey, KeyMap, ValidNetworks), KeyError> {
117        match self {
118            DescriptorKey::Public(public, valid_networks, _) => {
119                Ok((public, KeyMap::default(), valid_networks))
120            }
121            DescriptorKey::Secret(secret, valid_networks, _) => {
122                let mut key_map = KeyMap::new();
123
124                let public = secret
125                    .to_public(secp)
126                    .map_err(|e| miniscript::Error::Unexpected(e.to_string()))?;
127                key_map.insert(public.clone(), secret);
128
129                Ok((public, key_map, valid_networks))
130            }
131        }
132    }
133}
134
135/// Enum representation of the known valid [`ScriptContext`]s
136#[derive(Debug, Eq, PartialEq, Copy, Clone)]
137pub enum ScriptContextEnum {
138    /// Legacy scripts
139    Legacy,
140    /// Segwitv0 scripts
141    Segwitv0,
142    /// Taproot scripts
143    Tap,
144}
145
146impl ScriptContextEnum {
147    /// Returns whether the script context is [`ScriptContextEnum::Legacy`]
148    pub fn is_legacy(&self) -> bool {
149        self == &ScriptContextEnum::Legacy
150    }
151
152    /// Returns whether the script context is [`ScriptContextEnum::Segwitv0`]
153    pub fn is_segwit_v0(&self) -> bool {
154        self == &ScriptContextEnum::Segwitv0
155    }
156
157    /// Returns whether the script context is [`ScriptContextEnum::Tap`]
158    pub fn is_taproot(&self) -> bool {
159        self == &ScriptContextEnum::Tap
160    }
161}
162
163/// Trait that adds extra useful methods to [`ScriptContext`]s
164pub trait ExtScriptContext: ScriptContext {
165    /// Returns the [`ScriptContext`] as a [`ScriptContextEnum`]
166    fn as_enum() -> ScriptContextEnum;
167
168    /// Returns whether the script context is [`Legacy`](miniscript::Legacy)
169    fn is_legacy() -> bool {
170        Self::as_enum().is_legacy()
171    }
172
173    /// Returns whether the script context is [`Segwitv0`](miniscript::Segwitv0)
174    fn is_segwit_v0() -> bool {
175        Self::as_enum().is_segwit_v0()
176    }
177
178    /// Returns whether the script context is [`Tap`](miniscript::Tap), aka Taproot or Segwit V1
179    fn is_taproot() -> bool {
180        Self::as_enum().is_taproot()
181    }
182}
183
184impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
185    fn as_enum() -> ScriptContextEnum {
186        match TypeId::of::<Ctx>() {
187            t if t == TypeId::of::<miniscript::Legacy>() => ScriptContextEnum::Legacy,
188            t if t == TypeId::of::<miniscript::Segwitv0>() => ScriptContextEnum::Segwitv0,
189            t if t == TypeId::of::<miniscript::Tap>() => ScriptContextEnum::Tap,
190            _ => unimplemented!("Unknown ScriptContext type"),
191        }
192    }
193}
194
195/// Trait for objects that can be turned into a public or secret [`DescriptorKey`]
196///
197/// The generic type `Ctx` is used to define the context in which the key is valid: some key
198/// formats, like the mnemonics used by Electrum wallets, encode internally whether the wallet is
199/// legacy or segwit. Thus, trying to turn a valid legacy mnemonic into a `DescriptorKey`
200/// that would become part of a segwit descriptor should fail.
201///
202/// For key types that do care about this, the [`ExtScriptContext`] trait provides some useful
203/// methods that can be used to check at runtime which `Ctx` is being used.
204///
205/// For key types that can do this check statically (because they can only work within a
206/// single `Ctx`), the "specialized" trait can be implemented to make the compiler handle the type
207/// checking.
208///
209/// Keys also have control over the networks they support: constructing the return object with
210/// [`DescriptorKey::from_public`] or [`DescriptorKey::from_secret`] allows to specify a set of
211/// [`ValidNetworks`].
212///
213/// ## Examples
214///
215/// Key type valid in any context:
216///
217/// ```
218/// use bdk_wallet::bitcoin::PublicKey;
219///
220/// use bdk_wallet::keys::{DescriptorKey, IntoDescriptorKey, KeyError, ScriptContext};
221///
222/// pub struct MyKeyType {
223///     pubkey: PublicKey,
224/// }
225///
226/// impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
227///     fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
228///         self.pubkey.into_descriptor_key()
229///     }
230/// }
231/// ```
232///
233/// Key type that is only valid on mainnet:
234///
235/// ```
236/// use bdk_wallet::bitcoin::PublicKey;
237///
238/// use bdk_wallet::keys::{
239///     mainnet_network, DescriptorKey, DescriptorPublicKey, IntoDescriptorKey, KeyError,
240///     ScriptContext, SinglePub, SinglePubKey,
241/// };
242///
243/// pub struct MyKeyType {
244///     pubkey: PublicKey,
245/// }
246///
247/// impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
248///     fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
249///         Ok(DescriptorKey::from_public(
250///             DescriptorPublicKey::Single(SinglePub {
251///                 origin: None,
252///                 key: SinglePubKey::FullKey(self.pubkey),
253///             }),
254///             mainnet_network(),
255///         ))
256///     }
257/// }
258/// ```
259///
260/// Key type that internally encodes in which context it's valid. The context is checked at runtime:
261///
262/// ```
263/// use bdk_wallet::bitcoin::PublicKey;
264///
265/// use bdk_wallet::keys::{
266///     DescriptorKey, ExtScriptContext, IntoDescriptorKey, KeyError, ScriptContext,
267/// };
268///
269/// pub struct MyKeyType {
270///     is_legacy: bool,
271///     pubkey: PublicKey,
272/// }
273///
274/// impl<Ctx: ScriptContext + 'static> IntoDescriptorKey<Ctx> for MyKeyType {
275///     fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
276///         if Ctx::is_legacy() == self.is_legacy {
277///             self.pubkey.into_descriptor_key()
278///         } else {
279///             Err(KeyError::InvalidScriptContext)
280///         }
281///     }
282/// }
283/// ```
284///
285/// Key type that can only work within [`miniscript::Segwitv0`] context. Only the specialized
286/// version of the trait is implemented.
287///
288/// This example deliberately fails to compile, to demonstrate how the compiler can catch when keys
289/// are misused. In this case, the "segwit-only" key is used to build a `pkh()` descriptor, which
290/// makes the compiler (correctly) fail.
291///
292/// ```compile_fail
293/// use bdk_wallet::bitcoin::PublicKey;
294/// use core::str::FromStr;
295///
296/// use bdk_wallet::keys::{DescriptorKey, IntoDescriptorKey, KeyError};
297///
298/// pub struct MySegwitOnlyKeyType {
299///     pubkey: PublicKey,
300/// }
301///
302/// impl IntoDescriptorKey<bdk_wallet::miniscript::Segwitv0> for MySegwitOnlyKeyType {
303///     fn into_descriptor_key(self) -> Result<DescriptorKey<bdk_wallet::miniscript::Segwitv0>, KeyError> {
304///         self.pubkey.into_descriptor_key()
305///     }
306/// }
307///
308/// let key = MySegwitOnlyKeyType {
309///     pubkey: PublicKey::from_str("...")?,
310/// };
311/// let (descriptor, _, _) = bdk_wallet::descriptor!(pkh(key))?;
312/// //                                               ^^^^^ changing this to `wpkh` would make it compile
313///
314/// # Ok::<_, Box<dyn std::error::Error>>(())
315/// ```
316pub trait IntoDescriptorKey<Ctx: ScriptContext>: Sized {
317    /// Turn the key into a [`DescriptorKey`] within the requested [`ScriptContext`]
318    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
319}
320
321/// Enum for extended keys that can be either `xprv` or `xpub`
322///
323/// An instance of [`ExtendedKey`] can be constructed from an [`Xpriv`](bip32::Xpriv)
324/// or an [`Xpub`](bip32::Xpub) by using the `From` trait.
325///
326/// Defaults to the [`Legacy`](miniscript::Legacy) context.
327pub enum ExtendedKey<Ctx: ScriptContext = miniscript::Legacy> {
328    /// A private extended key, aka an `xprv`
329    Private((bip32::Xpriv, PhantomData<Ctx>)),
330    /// A public extended key, aka an `xpub`
331    Public((bip32::Xpub, PhantomData<Ctx>)),
332}
333
334impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
335    /// Return whether or not the key contains the private data
336    pub fn has_secret(&self) -> bool {
337        match self {
338            ExtendedKey::Private(_) => true,
339            ExtendedKey::Public(_) => false,
340        }
341    }
342
343    /// Transform the [`ExtendedKey`] into an [`Xpriv`](bip32::Xpriv) for the
344    /// given [`Network`], if the key contains the private data
345    pub fn into_xprv(self, network: Network) -> Option<bip32::Xpriv> {
346        match self {
347            ExtendedKey::Private((mut xprv, _)) => {
348                xprv.network = network.into();
349                Some(xprv)
350            }
351            ExtendedKey::Public(_) => None,
352        }
353    }
354
355    /// Transform the [`ExtendedKey`] into an [`Xpub`](bip32::Xpub) for the
356    /// given [`Network`]
357    pub fn into_xpub<C: Signing>(
358        self,
359        network: bitcoin::Network,
360        secp: &Secp256k1<C>,
361    ) -> bip32::Xpub {
362        let mut xpub = match self {
363            ExtendedKey::Private((xprv, _)) => bip32::Xpub::from_priv(secp, &xprv),
364            ExtendedKey::Public((xpub, _)) => xpub,
365        };
366
367        xpub.network = network.into();
368        xpub
369    }
370}
371
372impl<Ctx: ScriptContext> From<bip32::Xpub> for ExtendedKey<Ctx> {
373    fn from(xpub: bip32::Xpub) -> Self {
374        ExtendedKey::Public((xpub, PhantomData))
375    }
376}
377
378impl<Ctx: ScriptContext> From<bip32::Xpriv> for ExtendedKey<Ctx> {
379    fn from(xprv: bip32::Xpriv) -> Self {
380        ExtendedKey::Private((xprv, PhantomData))
381    }
382}
383
384/// Trait for keys that can be derived.
385///
386/// When extra metadata are provided, a [`DerivableKey`] can be transformed into a
387/// [`DescriptorKey`]: the trait [`IntoDescriptorKey`] is automatically implemented
388/// for `(DerivableKey, DerivationPath)` and
389/// `(DerivableKey, KeySource, DerivationPath)` tuples.
390///
391/// For key types that don't encode any indication about the path to use (like bip39), it's
392/// generally recommended to implement this trait instead of [`IntoDescriptorKey`]. The same
393/// rules regarding script context and valid networks apply.
394///
395/// ## Examples
396///
397/// Key types that can be directly converted into an [`Xpriv`] or
398/// an [`Xpub`] can implement only the required `into_extended_key()` method.
399///
400/// ```
401/// use bdk_wallet::bitcoin;
402/// use bdk_wallet::bitcoin::bip32;
403/// use bdk_wallet::keys::{DerivableKey, ExtendedKey, KeyError, ScriptContext};
404///
405/// struct MyCustomKeyType {
406///     key_data: bitcoin::PrivateKey,
407///     chain_code: [u8; 32],
408///     network: bitcoin::Network,
409/// }
410///
411/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
412///     fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
413///         let xprv = bip32::Xpriv {
414///             network: self.network.into(),
415///             depth: 0,
416///             parent_fingerprint: bip32::Fingerprint::default(),
417///             private_key: self.key_data.inner,
418///             chain_code: bip32::ChainCode::from(&self.chain_code),
419///             child_number: bip32::ChildNumber::Normal { index: 0 },
420///         };
421///
422///         xprv.into_extended_key()
423///     }
424/// }
425/// ```
426///
427/// Types that don't internally encode the [`Network`] in which they are valid need some extra
428/// steps to override the set of valid networks, otherwise only the network specified in the
429/// [`Xpriv`] or [`Xpub`] will be considered valid.
430///
431/// ```
432/// use bdk_wallet::bitcoin;
433/// use bdk_wallet::bitcoin::bip32;
434/// use bdk_wallet::keys::{
435///     any_network, DerivableKey, DescriptorKey, ExtendedKey, KeyError, ScriptContext,
436/// };
437///
438/// struct MyCustomKeyType {
439///     key_data: bitcoin::PrivateKey,
440///     chain_code: [u8; 32],
441/// }
442///
443/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
444///     fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
445///         let xprv = bip32::Xpriv {
446///             network: bitcoin::Network::Bitcoin.into(), // pick an arbitrary network here
447///             depth: 0,
448///             parent_fingerprint: bip32::Fingerprint::default(),
449///             private_key: self.key_data.inner,
450///             chain_code: bip32::ChainCode::from(&self.chain_code),
451///             child_number: bip32::ChildNumber::Normal { index: 0 },
452///         };
453///
454///         xprv.into_extended_key()
455///     }
456///
457///     fn into_descriptor_key(
458///         self,
459///         source: Option<bip32::KeySource>,
460///         derivation_path: bip32::DerivationPath,
461///     ) -> Result<DescriptorKey<Ctx>, KeyError> {
462///         let descriptor_key = self
463///             .into_extended_key()?
464///             .into_descriptor_key(source, derivation_path)?;
465///
466///         // Override the set of valid networks here
467///         Ok(descriptor_key.override_valid_networks(any_network()))
468///     }
469/// }
470/// ```
471///
472/// [`DerivationPath`]: (bip32::DerivationPath)
473/// [`Xpriv`]: (bip32::Xpriv)
474/// [`Xpub`]: (bip32::Xpub)
475pub trait DerivableKey<Ctx: ScriptContext = miniscript::Legacy>: Sized {
476    /// Consume `self` and turn it into an [`ExtendedKey`]
477    #[cfg_attr(
478        feature = "keys-bip39",
479        doc = r##"
480This can be used to get direct access to `xprv`s and `xpub`s for types that implement this trait,
481like [`Mnemonic`](bip39::Mnemonic) when the `keys-bip39` feature is enabled.
482```rust
483use bdk_wallet::bitcoin::Network;
484use bdk_wallet::keys::{DerivableKey, ExtendedKey};
485use bdk_wallet::keys::bip39::{Mnemonic, Language};
486
487# fn main() -> Result<(), Box<dyn std::error::Error>> {
488let xkey: ExtendedKey =
489    Mnemonic::parse_in(
490        Language::English,
491        "jelly crash boy whisper mouse ecology tuna soccer memory million news short",
492    )?
493    .into_extended_key()?;
494let xprv = xkey.into_xprv(Network::Bitcoin).unwrap();
495# Ok(()) }
496```
497"##
498    )]
499    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError>;
500
501    /// Consume `self` and turn it into a [`DescriptorKey`] by adding the extra metadata, such as
502    /// key origin and derivation path
503    fn into_descriptor_key(
504        self,
505        origin: Option<bip32::KeySource>,
506        derivation_path: bip32::DerivationPath,
507    ) -> Result<DescriptorKey<Ctx>, KeyError> {
508        match self.into_extended_key()? {
509            ExtendedKey::Private((xprv, _)) => DescriptorSecretKey::XPrv(DescriptorXKey {
510                origin,
511                xkey: xprv,
512                derivation_path,
513                wildcard: Wildcard::Unhardened,
514            })
515            .into_descriptor_key(),
516            ExtendedKey::Public((xpub, _)) => DescriptorPublicKey::XPub(DescriptorXKey {
517                origin,
518                xkey: xpub,
519                derivation_path,
520                wildcard: Wildcard::Unhardened,
521            })
522            .into_descriptor_key(),
523        }
524    }
525}
526
527/// Identity conversion
528impl<Ctx: ScriptContext> DerivableKey<Ctx> for ExtendedKey<Ctx> {
529    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
530        Ok(self)
531    }
532}
533
534impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpub {
535    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
536        Ok(self.into())
537    }
538}
539
540impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpriv {
541    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
542        Ok(self.into())
543    }
544}
545
546/// Output of a [`GeneratableKey`] key generation
547pub struct GeneratedKey<K, Ctx: ScriptContext> {
548    key: K,
549    valid_networks: ValidNetworks,
550    phantom: PhantomData<Ctx>,
551}
552
553impl<K, Ctx: ScriptContext> GeneratedKey<K, Ctx> {
554    fn new(key: K, valid_networks: ValidNetworks) -> Self {
555        GeneratedKey {
556            key,
557            valid_networks,
558            phantom: PhantomData,
559        }
560    }
561
562    /// Consumes `self` and returns the key
563    pub fn into_key(self) -> K {
564        self.key
565    }
566}
567
568impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx> {
569    type Target = K;
570
571    fn deref(&self) -> &Self::Target {
572        &self.key
573    }
574}
575
576impl<K: Clone, Ctx: ScriptContext> Clone for GeneratedKey<K, Ctx> {
577    fn clone(&self) -> GeneratedKey<K, Ctx> {
578        GeneratedKey {
579            key: self.key.clone(),
580            valid_networks: self.valid_networks.clone(),
581            phantom: self.phantom,
582        }
583    }
584}
585
586// Make generated "derivable" keys themselves "derivable". Also make sure they are assigned the
587// right `valid_networks`.
588impl<Ctx, K> DerivableKey<Ctx> for GeneratedKey<K, Ctx>
589where
590    Ctx: ScriptContext,
591    K: DerivableKey<Ctx>,
592{
593    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
594        self.key.into_extended_key()
595    }
596
597    fn into_descriptor_key(
598        self,
599        origin: Option<bip32::KeySource>,
600        derivation_path: bip32::DerivationPath,
601    ) -> Result<DescriptorKey<Ctx>, KeyError> {
602        let descriptor_key = self.key.into_descriptor_key(origin, derivation_path)?;
603        Ok(descriptor_key.override_valid_networks(self.valid_networks))
604    }
605}
606
607// Make generated keys directly usable in descriptors, and make sure they get assigned the right
608// `valid_networks`.
609impl<Ctx, K> IntoDescriptorKey<Ctx> for GeneratedKey<K, Ctx>
610where
611    Ctx: ScriptContext,
612    K: IntoDescriptorKey<Ctx>,
613{
614    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
615        let desc_key = self.key.into_descriptor_key()?;
616        Ok(desc_key.override_valid_networks(self.valid_networks))
617    }
618}
619
620/// Trait for keys that can be generated
621///
622/// The same rules about [`ScriptContext`] and [`ValidNetworks`] from [`IntoDescriptorKey`] apply.
623///
624/// This trait is particularly useful when combined with [`DerivableKey`]: if `Self`
625/// implements it, the returned [`GeneratedKey`] will also implement it. The same is true for
626/// [`IntoDescriptorKey`]: the generated keys can be directly used in descriptors if `Self` is also
627/// [`IntoDescriptorKey`].
628pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
629    /// Type specifying the amount of entropy required e.g. `[u8;32]`
630    type Entropy: AsMut<[u8]> + Default;
631
632    /// Extra options required by the `generate_with_entropy`
633    type Options;
634    /// Returned error in case of failure
635    type Error: core::fmt::Debug;
636
637    /// Generate a key given the extra options and the entropy
638    fn generate_with_entropy(
639        options: Self::Options,
640        entropy: Self::Entropy,
641    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error>;
642
643    /// Generate a key given the options with random entropy.
644    ///
645    /// Uses the thread-local random number generator.
646    #[cfg(feature = "std")]
647    fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
648        Self::generate_with_aux_rand(options, &mut bitcoin::key::rand::thread_rng())
649    }
650
651    /// Generate a key given the options with random entropy.
652    ///
653    /// Uses a provided random number generator (rng).
654    fn generate_with_aux_rand(
655        options: Self::Options,
656        rng: &mut (impl CryptoRng + RngCore),
657    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
658        let mut entropy = Self::Entropy::default();
659        rng.fill_bytes(entropy.as_mut());
660        Self::generate_with_entropy(options, entropy)
661    }
662}
663
664/// Trait that allows generating a key with the default options
665///
666/// This trait is automatically implemented if the [`GeneratableKey::Options`] implements
667/// [`Default`].
668pub trait GeneratableDefaultOptions<Ctx>: GeneratableKey<Ctx>
669where
670    Ctx: ScriptContext,
671    <Self as GeneratableKey<Ctx>>::Options: Default,
672{
673    /// Generate a key with the default options and a given entropy
674    fn generate_with_entropy_default(
675        entropy: Self::Entropy,
676    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
677        Self::generate_with_entropy(Default::default(), entropy)
678    }
679
680    /// Generate a key with the default options and a random entropy
681    ///
682    /// Uses the thread-local random number generator.
683    #[cfg(feature = "std")]
684    fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
685        Self::generate_with_aux_rand(Default::default(), &mut bitcoin::key::rand::thread_rng())
686    }
687
688    /// Generate a key with the default options and a random entropy
689    ///
690    /// Uses a provided random number generator (rng).
691    fn generate_default_with_aux_rand(
692        rng: &mut (impl CryptoRng + RngCore),
693    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
694        Self::generate_with_aux_rand(Default::default(), rng)
695    }
696}
697
698/// Automatic implementation of [`GeneratableDefaultOptions`] for [`GeneratableKey`]s where
699/// `Options` implements `Default`
700impl<Ctx, K> GeneratableDefaultOptions<Ctx> for K
701where
702    Ctx: ScriptContext,
703    K: GeneratableKey<Ctx>,
704    <K as GeneratableKey<Ctx>>::Options: Default,
705{
706}
707
708impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
709    type Entropy = [u8; 32];
710
711    type Options = ();
712    type Error = bip32::Error;
713
714    fn generate_with_entropy(
715        _: Self::Options,
716        entropy: Self::Entropy,
717    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
718        // pick a arbitrary network here, but say that we support all of them
719        let xprv = bip32::Xpriv::new_master(Network::Bitcoin, entropy.as_ref())?;
720        Ok(GeneratedKey::new(xprv, any_network()))
721    }
722}
723
724/// Options for generating a [`PrivateKey`]
725///
726/// Defaults to creating compressed keys, which save on-chain bytes and fees
727#[derive(Debug, Copy, Clone)]
728pub struct PrivateKeyGenerateOptions {
729    /// Whether the generated key should be "compressed" or not
730    pub compressed: bool,
731}
732
733impl Default for PrivateKeyGenerateOptions {
734    fn default() -> Self {
735        PrivateKeyGenerateOptions { compressed: true }
736    }
737}
738
739impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
740    type Entropy = [u8; secp256k1::constants::SECRET_KEY_SIZE];
741
742    type Options = PrivateKeyGenerateOptions;
743    type Error = bip32::Error;
744
745    fn generate_with_entropy(
746        options: Self::Options,
747        entropy: Self::Entropy,
748    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
749        // pick a arbitrary network here, but say that we support all of them
750        let inner = secp256k1::SecretKey::from_slice(&entropy)?;
751        let private_key = PrivateKey {
752            compressed: options.compressed,
753            network: Network::Bitcoin.into(),
754            inner,
755        };
756
757        Ok(GeneratedKey::new(private_key, any_network()))
758    }
759}
760
761impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
762    for (T, bip32::DerivationPath)
763{
764    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
765        self.0.into_descriptor_key(None, self.1)
766    }
767}
768
769impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
770    for (T, bip32::KeySource, bip32::DerivationPath)
771{
772    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
773        self.0.into_descriptor_key(Some(self.1), self.2)
774    }
775}
776
777fn expand_multi_keys<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
778    pks: Vec<Pk>,
779    secp: &SecpCtx,
780) -> Result<(Vec<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError> {
781    let (pks, key_maps_networks): (Vec<_>, Vec<_>) = pks
782        .into_iter()
783        .map(|key| key.into_descriptor_key()?.extract(secp))
784        .collect::<Result<Vec<_>, _>>()?
785        .into_iter()
786        .map(|(a, b, c)| (a, (b, c)))
787        .unzip();
788
789    let (key_map, valid_networks) = key_maps_networks.into_iter().fold(
790        (KeyMap::default(), any_network()),
791        |(mut keys_acc, net_acc), (key, net)| {
792            keys_acc.extend(key);
793            let net_acc = merge_networks(&net_acc, &net);
794
795            (keys_acc, net_acc)
796        },
797    );
798
799    Ok((pks, key_map, valid_networks))
800}
801
802// Used internally by `bdk_wallet::fragment!` to build `pk_k()` fragments
803#[doc(hidden)]
804pub fn make_pk<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
805    descriptor_key: Pk,
806    secp: &SecpCtx,
807) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
808    let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?;
809    let minisc = Miniscript::from_ast(Terminal::PkK(key))?;
810
811    minisc.check_miniscript()?;
812
813    Ok((minisc, key_map, valid_networks))
814}
815
816// Used internally by `bdk_wallet::fragment!` to build `pk_h()` fragments
817#[doc(hidden)]
818pub fn make_pkh<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
819    descriptor_key: Pk,
820    secp: &SecpCtx,
821) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
822    let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?;
823    let minisc = Miniscript::from_ast(Terminal::PkH(key))?;
824
825    minisc.check_miniscript()?;
826
827    Ok((minisc, key_map, valid_networks))
828}
829
830// Used internally by `bdk_wallet::fragment!` to build `multi()` fragments
831#[doc(hidden)]
832pub fn make_multi<
833    Pk: IntoDescriptorKey<Ctx>,
834    Ctx: ScriptContext,
835    V: Fn(usize, Vec<DescriptorPublicKey>) -> Terminal<DescriptorPublicKey, Ctx>,
836>(
837    thresh: usize,
838    variant: V,
839    pks: Vec<Pk>,
840    secp: &SecpCtx,
841) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
842    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
843    let minisc = Miniscript::from_ast(variant(thresh, pks))?;
844
845    minisc.check_miniscript()?;
846
847    Ok((minisc, key_map, valid_networks))
848}
849
850// Used internally by `bdk_wallet::descriptor!` to build `sortedmulti()` fragments
851#[doc(hidden)]
852pub fn make_sortedmulti<Pk, Ctx, F>(
853    thresh: usize,
854    pks: Vec<Pk>,
855    build_desc: F,
856    secp: &SecpCtx,
857) -> Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>
858where
859    Pk: IntoDescriptorKey<Ctx>,
860    Ctx: ScriptContext,
861    F: Fn(
862        usize,
863        Vec<DescriptorPublicKey>,
864    ) -> Result<(Descriptor<DescriptorPublicKey>, PhantomData<Ctx>), DescriptorError>,
865{
866    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
867    let descriptor = build_desc(thresh, pks)?.0;
868
869    Ok((descriptor, key_map, valid_networks))
870}
871
872/// The "identity" conversion is used internally by some `bdk_wallet::fragment`s
873impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorKey<Ctx> {
874    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
875        Ok(self)
876    }
877}
878
879impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorPublicKey {
880    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
881        let networks = match self {
882            DescriptorPublicKey::Single(_) => any_network(),
883            DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) => {
884                if xkey.network.is_mainnet() {
885                    mainnet_network()
886                } else {
887                    test_networks()
888                }
889            }
890            DescriptorPublicKey::MultiXPub(DescriptorMultiXKey { xkey, .. }) => {
891                if xkey.network.is_mainnet() {
892                    mainnet_network()
893                } else {
894                    test_networks()
895                }
896            }
897        };
898
899        Ok(DescriptorKey::from_public(self, networks))
900    }
901}
902
903impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PublicKey {
904    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
905        DescriptorPublicKey::Single(SinglePub {
906            key: SinglePubKey::FullKey(self),
907            origin: None,
908        })
909        .into_descriptor_key()
910    }
911}
912
913impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for XOnlyPublicKey {
914    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
915        DescriptorPublicKey::Single(SinglePub {
916            key: SinglePubKey::XOnly(self),
917            origin: None,
918        })
919        .into_descriptor_key()
920    }
921}
922
923impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorSecretKey {
924    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
925        let networks = match &self {
926            DescriptorSecretKey::Single(sk) if sk.key.network.is_mainnet() => mainnet_network(),
927            DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. }) if xkey.network.is_mainnet() => {
928                mainnet_network()
929            }
930            _ => test_networks(),
931        };
932
933        Ok(DescriptorKey::from_secret(self, networks))
934    }
935}
936
937impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for &'_ str {
938    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
939        DescriptorSecretKey::from_str(self)
940            .map_err(|e| KeyError::Message(e.to_string()))?
941            .into_descriptor_key()
942    }
943}
944
945impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PrivateKey {
946    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
947        DescriptorSecretKey::Single(SinglePriv {
948            key: self,
949            origin: None,
950        })
951        .into_descriptor_key()
952    }
953}
954
955/// Errors thrown while working with [`keys`](crate::keys)
956#[derive(Debug, PartialEq)]
957pub enum KeyError {
958    /// The key cannot exist in the given script context
959    InvalidScriptContext,
960    /// The key is not valid for the given network
961    InvalidNetwork,
962    /// The key has an invalid checksum
963    InvalidChecksum,
964
965    /// Custom error message
966    Message(String),
967
968    /// BIP32 error
969    Bip32(bitcoin::bip32::Error),
970    /// Miniscript error
971    Miniscript(miniscript::Error),
972}
973
974impl From<miniscript::Error> for KeyError {
975    fn from(err: miniscript::Error) -> Self {
976        KeyError::Miniscript(err)
977    }
978}
979
980impl From<bip32::Error> for KeyError {
981    fn from(err: bip32::Error) -> Self {
982        KeyError::Bip32(err)
983    }
984}
985
986impl fmt::Display for KeyError {
987    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988        match self {
989            Self::InvalidScriptContext => write!(f, "Invalid script context"),
990            Self::InvalidNetwork => write!(f, "Invalid network"),
991            Self::InvalidChecksum => write!(f, "Invalid checksum"),
992            Self::Message(err) => write!(f, "{err}"),
993            Self::Bip32(err) => write!(f, "BIP32 error: {err}"),
994            Self::Miniscript(err) => write!(f, "Miniscript error: {err}"),
995        }
996    }
997}
998
999#[cfg(feature = "std")]
1000impl std::error::Error for KeyError {}
1001
1002#[cfg(test)]
1003mod test {
1004    use bitcoin::bip32;
1005
1006    use super::*;
1007
1008    pub const TEST_ENTROPY: [u8; 32] = [0xAA; 32];
1009
1010    #[test]
1011    fn test_keys_generate_xprv() {
1012        let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
1013            bip32::Xpriv::generate_with_entropy_default(TEST_ENTROPY).unwrap();
1014
1015        assert_eq!(generated_xprv.valid_networks, any_network());
1016        assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");
1017    }
1018
1019    #[test]
1020    fn test_keys_generate_wif() {
1021        let generated_wif: GeneratedKey<_, miniscript::Segwitv0> =
1022            bitcoin::PrivateKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
1023
1024        assert_eq!(generated_wif.valid_networks, any_network());
1025        assert_eq!(
1026            generated_wif.to_string(),
1027            "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"
1028        );
1029    }
1030
1031    #[cfg(feature = "keys-bip39")]
1032    #[test]
1033    fn test_keys_wif_network_bip39() {
1034        let xkey: ExtendedKey = bip39::Mnemonic::parse_in(
1035            bip39::Language::English,
1036            "jelly crash boy whisper mouse ecology tuna soccer memory million news short",
1037        )
1038        .unwrap()
1039        .into_extended_key()
1040        .unwrap();
1041        let xprv = xkey.into_xprv(Network::Testnet).unwrap();
1042
1043        assert_eq!(xprv.network, Network::Testnet.into());
1044    }
1045}