use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::any::TypeId;
use core::fmt;
use core::marker::PhantomData;
use core::ops::Deref;
use core::str::FromStr;
use crate::collections::HashSet;
use crate::descriptor::{CheckMiniscript, DescriptorError};
use crate::wallet::utils::SecpCtx;
use bitcoin::{
bip32,
key::XOnlyPublicKey,
secp256k1::{self, Secp256k1, Signing},
NetworkKind, PrivateKey, PublicKey,
};
use miniscript::{
descriptor::{Descriptor, DescriptorMultiXKey, DescriptorXKey, Wildcard},
{Miniscript, Terminal},
};
use rand_core::{CryptoRng, RngCore};
pub use miniscript::descriptor::{
DescriptorPublicKey, DescriptorSecretKey, KeyMap, SinglePriv, SinglePub, SinglePubKey,
SortedMultiVec,
};
pub use miniscript::ScriptContext;
#[cfg(feature = "keys-bip39")]
#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
pub mod bip39;
pub type ValidNetworkKinds = HashSet<NetworkKind>;
pub fn any_network_kind() -> ValidNetworkKinds {
vec![NetworkKind::Main, NetworkKind::Test]
.into_iter()
.collect()
}
pub fn mainnet_network_kind() -> ValidNetworkKinds {
vec![NetworkKind::Main].into_iter().collect()
}
pub fn test_network_kind() -> ValidNetworkKinds {
vec![NetworkKind::Test].into_iter().collect()
}
pub fn intersect_network_kinds(a: &ValidNetworkKinds, b: &ValidNetworkKinds) -> ValidNetworkKinds {
a.intersection(b).cloned().collect()
}
#[derive(Debug)]
pub enum DescriptorKey<Ctx: ScriptContext> {
#[doc(hidden)]
Public(DescriptorPublicKey, ValidNetworkKinds, PhantomData<Ctx>),
#[doc(hidden)]
Secret(DescriptorSecretKey, ValidNetworkKinds, PhantomData<Ctx>),
}
impl<Ctx: ScriptContext> DescriptorKey<Ctx> {
pub fn from_public(public: DescriptorPublicKey, network_kinds: ValidNetworkKinds) -> Self {
DescriptorKey::Public(public, network_kinds, PhantomData)
}
pub fn from_secret(secret: DescriptorSecretKey, network_kinds: ValidNetworkKinds) -> Self {
DescriptorKey::Secret(secret, network_kinds, PhantomData)
}
pub fn override_valid_network_kinds(self, network_kinds: ValidNetworkKinds) -> Self {
match self {
DescriptorKey::Public(key, _, _) => {
DescriptorKey::Public(key, network_kinds, PhantomData)
}
DescriptorKey::Secret(key, _, _) => {
DescriptorKey::Secret(key, network_kinds, PhantomData)
}
}
}
#[doc(hidden)]
pub fn extract(
self,
secp: &SecpCtx,
) -> Result<(DescriptorPublicKey, KeyMap, ValidNetworkKinds), KeyError> {
match self {
DescriptorKey::Public(public, valid_network_kinds, _) => {
Ok((public, KeyMap::default(), valid_network_kinds))
}
DescriptorKey::Secret(secret, valid_network_kinds, _) => {
let mut key_map = KeyMap::new();
let public = secret
.to_public(secp)
.map_err(|e| miniscript::Error::Unexpected(e.to_string()))?;
key_map.insert(public.clone(), secret);
Ok((public, key_map, valid_network_kinds))
}
}
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ScriptContextEnum {
Legacy,
Segwitv0,
Tap,
}
impl ScriptContextEnum {
pub fn is_legacy(&self) -> bool {
self == &ScriptContextEnum::Legacy
}
pub fn is_segwit_v0(&self) -> bool {
self == &ScriptContextEnum::Segwitv0
}
pub fn is_taproot(&self) -> bool {
self == &ScriptContextEnum::Tap
}
}
pub trait ExtScriptContext: ScriptContext {
fn as_enum() -> ScriptContextEnum;
fn is_legacy() -> bool {
Self::as_enum().is_legacy()
}
fn is_segwit_v0() -> bool {
Self::as_enum().is_segwit_v0()
}
fn is_taproot() -> bool {
Self::as_enum().is_taproot()
}
}
impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
fn as_enum() -> ScriptContextEnum {
match TypeId::of::<Ctx>() {
t if t == TypeId::of::<miniscript::Legacy>() => ScriptContextEnum::Legacy,
t if t == TypeId::of::<miniscript::Segwitv0>() => ScriptContextEnum::Segwitv0,
t if t == TypeId::of::<miniscript::Tap>() => ScriptContextEnum::Tap,
_ => unimplemented!("Unknown ScriptContext type"),
}
}
}
pub trait IntoDescriptorKey<Ctx: ScriptContext>: Sized {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
}
pub enum ExtendedKey<Ctx: ScriptContext = miniscript::Legacy> {
Private((bip32::Xpriv, PhantomData<Ctx>)),
Public((bip32::Xpub, PhantomData<Ctx>)),
}
impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
pub fn has_secret(&self) -> bool {
match self {
ExtendedKey::Private(_) => true,
ExtendedKey::Public(_) => false,
}
}
pub fn into_xprv(self, network_kind: NetworkKind) -> Option<bip32::Xpriv> {
match self {
ExtendedKey::Private((mut xprv, _)) => {
xprv.network = network_kind;
Some(xprv)
}
ExtendedKey::Public(_) => None,
}
}
pub fn into_xpub<C: Signing>(
self,
network_kind: NetworkKind,
secp: &Secp256k1<C>,
) -> bip32::Xpub {
let mut xpub = match self {
ExtendedKey::Private((xprv, _)) => bip32::Xpub::from_priv(secp, &xprv),
ExtendedKey::Public((xpub, _)) => xpub,
};
xpub.network = network_kind;
xpub
}
}
impl<Ctx: ScriptContext> From<bip32::Xpub> for ExtendedKey<Ctx> {
fn from(xpub: bip32::Xpub) -> Self {
ExtendedKey::Public((xpub, PhantomData))
}
}
impl<Ctx: ScriptContext> From<bip32::Xpriv> for ExtendedKey<Ctx> {
fn from(xprv: bip32::Xpriv) -> Self {
ExtendedKey::Private((xprv, PhantomData))
}
}
pub trait DerivableKey<Ctx: ScriptContext = miniscript::Legacy>: Sized {
#[cfg_attr(
feature = "keys-bip39",
doc = r##"
This can be used to get direct access to `xprv`s and `xpub`s for types that implement this trait,
like [`Mnemonic`](bip39::Mnemonic) when the `keys-bip39` feature is enabled.
```rust
use bdk_wallet::bitcoin::NetworkKind;
use bdk_wallet::keys::{DerivableKey, ExtendedKey};
use bdk_wallet::keys::bip39::{Mnemonic, Language};
# fn main() -> Result<(), Box<dyn core::error::Error>> {
let xkey: ExtendedKey =
Mnemonic::parse_in(
Language::English,
"jelly crash boy whisper mouse ecology tuna soccer memory million news short",
)?
.into_extended_key()?;
let xprv = xkey.into_xprv(NetworkKind::Main).unwrap();
# Ok(()) }
```
"##
)]
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError>;
fn into_descriptor_key(
self,
origin: Option<bip32::KeySource>,
derivation_path: bip32::DerivationPath,
) -> Result<DescriptorKey<Ctx>, KeyError> {
match self.into_extended_key()? {
ExtendedKey::Private((xprv, _)) => DescriptorSecretKey::XPrv(DescriptorXKey {
origin,
xkey: xprv,
derivation_path,
wildcard: Wildcard::Unhardened,
})
.into_descriptor_key(),
ExtendedKey::Public((xpub, _)) => DescriptorPublicKey::XPub(DescriptorXKey {
origin,
xkey: xpub,
derivation_path,
wildcard: Wildcard::Unhardened,
})
.into_descriptor_key(),
}
}
}
impl<Ctx: ScriptContext> DerivableKey<Ctx> for ExtendedKey<Ctx> {
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
Ok(self)
}
}
impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpub {
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
Ok(self.into())
}
}
impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpriv {
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
Ok(self.into())
}
}
pub struct GeneratedKey<K, Ctx: ScriptContext> {
key: K,
valid_network_kinds: ValidNetworkKinds,
phantom: PhantomData<Ctx>,
}
impl<K, Ctx: ScriptContext> GeneratedKey<K, Ctx> {
fn new(key: K, valid_network_kinds: ValidNetworkKinds) -> Self {
GeneratedKey {
key,
valid_network_kinds,
phantom: PhantomData,
}
}
pub fn into_key(self) -> K {
self.key
}
}
impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx> {
type Target = K;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl<K: Clone, Ctx: ScriptContext> Clone for GeneratedKey<K, Ctx> {
fn clone(&self) -> GeneratedKey<K, Ctx> {
GeneratedKey {
key: self.key.clone(),
valid_network_kinds: self.valid_network_kinds.clone(),
phantom: self.phantom,
}
}
}
impl<Ctx, K> DerivableKey<Ctx> for GeneratedKey<K, Ctx>
where
Ctx: ScriptContext,
K: DerivableKey<Ctx>,
{
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
self.key.into_extended_key()
}
fn into_descriptor_key(
self,
origin: Option<bip32::KeySource>,
derivation_path: bip32::DerivationPath,
) -> Result<DescriptorKey<Ctx>, KeyError> {
let descriptor_key = self.key.into_descriptor_key(origin, derivation_path)?;
Ok(descriptor_key.override_valid_network_kinds(self.valid_network_kinds))
}
}
impl<Ctx, K> IntoDescriptorKey<Ctx> for GeneratedKey<K, Ctx>
where
Ctx: ScriptContext,
K: IntoDescriptorKey<Ctx>,
{
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let desc_key = self.key.into_descriptor_key()?;
Ok(desc_key.override_valid_network_kinds(self.valid_network_kinds))
}
}
pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
type Entropy: AsMut<[u8]> + Default;
type Options;
type Error: core::fmt::Debug;
fn generate_with_entropy(
options: Self::Options,
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error>;
#[cfg(feature = "std")]
fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate_with_aux_rand(options, &mut bitcoin::key::rand::thread_rng())
}
fn generate_with_aux_rand(
options: Self::Options,
rng: &mut (impl CryptoRng + RngCore),
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
let mut entropy = Self::Entropy::default();
rng.fill_bytes(entropy.as_mut());
Self::generate_with_entropy(options, entropy)
}
}
pub trait GeneratableDefaultOptions<Ctx>: GeneratableKey<Ctx>
where
Ctx: ScriptContext,
<Self as GeneratableKey<Ctx>>::Options: Default,
{
fn generate_with_entropy_default(
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate_with_entropy(Default::default(), entropy)
}
#[cfg(feature = "std")]
fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate_with_aux_rand(Default::default(), &mut bitcoin::key::rand::thread_rng())
}
fn generate_default_with_aux_rand(
rng: &mut (impl CryptoRng + RngCore),
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate_with_aux_rand(Default::default(), rng)
}
}
impl<Ctx, K> GeneratableDefaultOptions<Ctx> for K
where
Ctx: ScriptContext,
K: GeneratableKey<Ctx>,
<K as GeneratableKey<Ctx>>::Options: Default,
{
}
impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
type Entropy = [u8; 32];
type Options = XprivGenerateOptions;
type Error = bip32::Error;
fn generate_with_entropy(
options: Self::Options,
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
let (kind, valid_networks) = if options.network.is_mainnet() {
(NetworkKind::Main, mainnet_network_kind())
} else {
(NetworkKind::Test, test_network_kind())
};
let xprv = bip32::Xpriv::new_master(kind, entropy.as_ref())?;
Ok(GeneratedKey::new(xprv, valid_networks))
}
}
#[derive(Debug, Copy, Clone)]
pub struct XprivGenerateOptions {
pub network: NetworkKind,
}
impl Default for XprivGenerateOptions {
fn default() -> Self {
XprivGenerateOptions {
network: NetworkKind::Main,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct PrivateKeyGenerateOptions {
pub compressed: bool,
pub network: NetworkKind,
}
impl Default for PrivateKeyGenerateOptions {
fn default() -> Self {
PrivateKeyGenerateOptions {
compressed: true,
network: NetworkKind::Main,
}
}
}
impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
type Entropy = [u8; secp256k1::constants::SECRET_KEY_SIZE];
type Options = PrivateKeyGenerateOptions;
type Error = bip32::Error;
fn generate_with_entropy(
options: Self::Options,
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
let inner = secp256k1::SecretKey::from_slice(&entropy)?;
let private_key = PrivateKey {
compressed: options.compressed,
network: options.network,
inner,
};
let valid_networks = if private_key.network.is_mainnet() {
mainnet_network_kind()
} else {
test_network_kind()
};
Ok(GeneratedKey::new(private_key, valid_networks))
}
}
impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
for (T, bip32::DerivationPath)
{
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
self.0.into_descriptor_key(None, self.1)
}
}
impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
for (T, bip32::KeySource, bip32::DerivationPath)
{
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
self.0.into_descriptor_key(Some(self.1), self.2)
}
}
fn expand_multi_keys<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
pks: Vec<Pk>,
secp: &SecpCtx,
) -> Result<(Vec<DescriptorPublicKey>, KeyMap, ValidNetworkKinds), KeyError> {
let (pks, key_maps_network_kinds): (Vec<_>, Vec<_>) = pks
.into_iter()
.map(|key| key.into_descriptor_key()?.extract(secp))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.map(|(a, b, c)| (a, (b, c)))
.unzip();
let (key_map, valid_network_kinds) = key_maps_network_kinds.into_iter().fold(
(KeyMap::default(), any_network_kind()),
|(mut keys_acc, netkind_acc), (key, netkind)| {
keys_acc.extend(key);
let netkind_acc = intersect_network_kinds(&netkind_acc, &netkind);
(keys_acc, netkind_acc)
},
);
Ok((pks, key_map, valid_network_kinds))
}
#[doc(hidden)]
pub fn make_pk<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
descriptor_key: Pk,
secp: &SecpCtx,
) -> Result<
(
Miniscript<DescriptorPublicKey, Ctx>,
KeyMap,
ValidNetworkKinds,
),
DescriptorError,
> {
let (key, key_map, valid_network_kinds) =
descriptor_key.into_descriptor_key()?.extract(secp)?;
let minisc = Miniscript::from_ast(Terminal::PkK(key))?;
minisc.check_miniscript()?;
Ok((minisc, key_map, valid_network_kinds))
}
#[doc(hidden)]
pub fn make_pkh<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
descriptor_key: Pk,
secp: &SecpCtx,
) -> Result<
(
Miniscript<DescriptorPublicKey, Ctx>,
KeyMap,
ValidNetworkKinds,
),
DescriptorError,
> {
let (key, key_map, valid_network_kinds) =
descriptor_key.into_descriptor_key()?.extract(secp)?;
let minisc = Miniscript::from_ast(Terminal::PkH(key))?;
minisc.check_miniscript()?;
Ok((minisc, key_map, valid_network_kinds))
}
#[doc(hidden)]
pub fn make_multi<
Pk: IntoDescriptorKey<Ctx>,
Ctx: ScriptContext,
V: Fn(usize, Vec<DescriptorPublicKey>) -> Terminal<DescriptorPublicKey, Ctx>,
>(
thresh: usize,
variant: V,
pks: Vec<Pk>,
secp: &SecpCtx,
) -> Result<
(
Miniscript<DescriptorPublicKey, Ctx>,
KeyMap,
ValidNetworkKinds,
),
DescriptorError,
> {
let (pks, key_map, valid_network_kinds) = expand_multi_keys(pks, secp)?;
let minisc = Miniscript::from_ast(variant(thresh, pks))?;
minisc.check_miniscript()?;
Ok((minisc, key_map, valid_network_kinds))
}
#[doc(hidden)]
pub fn make_sortedmulti<Pk, Ctx, F>(
thresh: usize,
pks: Vec<Pk>,
build_desc: F,
secp: &SecpCtx,
) -> Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworkKinds), DescriptorError>
where
Pk: IntoDescriptorKey<Ctx>,
Ctx: ScriptContext,
F: Fn(
usize,
Vec<DescriptorPublicKey>,
) -> Result<(Descriptor<DescriptorPublicKey>, PhantomData<Ctx>), DescriptorError>,
{
let (pks, key_map, valid_network_kinds) = expand_multi_keys(pks, secp)?;
let descriptor = build_desc(thresh, pks)?.0;
Ok((descriptor, key_map, valid_network_kinds))
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorKey<Ctx> {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
Ok(self)
}
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorPublicKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let network_kinds = match self {
DescriptorPublicKey::Single(_) => any_network_kind(),
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) => {
if xkey.network.is_mainnet() {
mainnet_network_kind()
} else {
test_network_kind()
}
}
DescriptorPublicKey::MultiXPub(DescriptorMultiXKey { xkey, .. }) => {
if xkey.network.is_mainnet() {
mainnet_network_kind()
} else {
test_network_kind()
}
}
};
Ok(DescriptorKey::from_public(self, network_kinds))
}
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PublicKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorPublicKey::Single(SinglePub {
key: SinglePubKey::FullKey(self),
origin: None,
})
.into_descriptor_key()
}
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for XOnlyPublicKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorPublicKey::Single(SinglePub {
key: SinglePubKey::XOnly(self),
origin: None,
})
.into_descriptor_key()
}
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorSecretKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let network_kinds = match &self {
DescriptorSecretKey::Single(sk) if sk.key.network.is_mainnet() => {
mainnet_network_kind()
}
DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. }) if xkey.network.is_mainnet() => {
mainnet_network_kind()
}
_ => test_network_kind(),
};
Ok(DescriptorKey::from_secret(self, network_kinds))
}
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for &'_ str {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorSecretKey::from_str(self)
.map_err(|e| KeyError::Message(e.to_string()))?
.into_descriptor_key()
}
}
impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PrivateKey {
fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorSecretKey::Single(SinglePriv {
key: self,
origin: None,
})
.into_descriptor_key()
}
}
#[derive(Debug, PartialEq)]
pub enum KeyError {
InvalidScriptContext,
InvalidNetworkKind,
InvalidChecksum,
Message(String),
Bip32(bitcoin::bip32::Error),
Miniscript(miniscript::Error),
}
impl From<miniscript::Error> for KeyError {
fn from(err: miniscript::Error) -> Self {
KeyError::Miniscript(err)
}
}
impl From<bip32::Error> for KeyError {
fn from(err: bip32::Error) -> Self {
KeyError::Bip32(err)
}
}
impl fmt::Display for KeyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidScriptContext => write!(f, "Invalid script context"),
Self::InvalidNetworkKind => write!(f, "Invalid network kind"),
Self::InvalidChecksum => write!(f, "Invalid checksum"),
Self::Message(err) => write!(f, "{err}"),
Self::Bip32(err) => write!(f, "BIP32 error: {err}"),
Self::Miniscript(err) => write!(f, "Miniscript error: {err}"),
}
}
}
impl core::error::Error for KeyError {}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod test {
use super::*;
use bitcoin::bip32;
pub const TEST_ENTROPY: [u8; 32] = [0xAA; 32];
#[test]
fn test_xpriv_generate_options() {
use bitcoin::bip32::Xpriv;
let secp = SecpCtx::new();
let options = XprivGenerateOptions {
network: NetworkKind::Test,
};
let xpriv: GeneratedKey<Xpriv, miniscript::Segwitv0> = Xpriv::generate(options).unwrap();
let desc_key = xpriv
.into_descriptor_key(None, "m/84h/1h/0h".parse().unwrap())
.unwrap();
let desc_pk = desc_key.extract(&secp).unwrap().0;
assert!(desc_pk.to_string().contains("tpub"));
let options = XprivGenerateOptions {
network: NetworkKind::Main,
};
let xpriv: GeneratedKey<Xpriv, miniscript::Segwitv0> = Xpriv::generate(options).unwrap();
let desc_key = xpriv
.into_descriptor_key(None, "m/84h/1h/0h".parse().unwrap())
.unwrap();
let desc_pk = desc_key.extract(&secp).unwrap().0;
assert!(desc_pk.to_string().contains("xpub"));
}
#[test]
fn test_keys_generate_xprv() {
let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
bip32::Xpriv::generate_with_entropy_default(TEST_ENTROPY).unwrap();
assert_eq!(generated_xprv.valid_network_kinds, mainnet_network_kind());
assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");
}
#[test]
fn test_keys_generate_wif() {
let generated_wif: GeneratedKey<_, miniscript::Segwitv0> =
bitcoin::PrivateKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
assert_eq!(generated_wif.valid_network_kinds, mainnet_network_kind());
assert_eq!(
generated_wif.to_string(),
"L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"
);
}
#[cfg(feature = "keys-bip39")]
#[test]
fn test_keys_wif_network_kind_bip39() {
let xkey: ExtendedKey = bip39::Mnemonic::parse_in(
bip39::Language::English,
"jelly crash boy whisper mouse ecology tuna soccer memory million news short",
)
.unwrap()
.into_extended_key()
.unwrap();
let xprv = xkey.into_xprv(NetworkKind::Test).unwrap();
assert_eq!(xprv.network, NetworkKind::Test);
}
}