2022-06-29 04:05:31 +00:00
|
|
|
// SPDX-License-Identifier: CC0-1.0
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2021-11-05 21:58:18 +00:00
|
|
|
//! BIP32 implementation.
|
2016-06-24 19:15:57 +00:00
|
|
|
//!
|
|
|
|
//! Implementation of BIP32 hierarchical deterministic wallets, as defined
|
2021-11-05 21:58:18 +00:00
|
|
|
//! at <https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki>.
|
|
|
|
//!
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2022-01-21 01:50:01 +00:00
|
|
|
use core::ops::Index;
|
2022-08-24 06:16:34 +00:00
|
|
|
use core::str::FromStr;
|
2023-05-26 14:29:11 +00:00
|
|
|
use core::{fmt, slice};
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2023-08-21 23:27:17 +00:00
|
|
|
use hashes::{hash160, hash_newtype, sha512, Hash, HashEngine, Hmac, HmacEngine};
|
2023-03-28 01:16:47 +00:00
|
|
|
use internals::{impl_array_newtype, write_err};
|
2023-11-28 21:48:03 +00:00
|
|
|
use io::Write;
|
2024-02-20 05:11:14 +00:00
|
|
|
use secp256k1::{Secp256k1, XOnlyPublicKey};
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2024-01-14 07:40:44 +00:00
|
|
|
use crate::crypto::key::{CompressedPublicKey, Keypair, PrivateKey};
|
2022-09-20 06:07:58 +00:00
|
|
|
use crate::internal_macros::impl_bytes_newtype;
|
2024-02-20 05:11:14 +00:00
|
|
|
use crate::network::NetworkKind;
|
2024-03-31 01:03:18 +00:00
|
|
|
use crate::prelude::*;
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2023-08-21 23:20:49 +00:00
|
|
|
/// Version bytes for extended public keys on the Bitcoin network.
|
|
|
|
const VERSION_BYTES_MAINNET_PUBLIC: [u8; 4] = [0x04, 0x88, 0xB2, 0x1E];
|
|
|
|
/// Version bytes for extended private keys on the Bitcoin network.
|
|
|
|
const VERSION_BYTES_MAINNET_PRIVATE: [u8; 4] = [0x04, 0x88, 0xAD, 0xE4];
|
|
|
|
/// Version bytes for extended public keys on any of the testnet networks.
|
|
|
|
const VERSION_BYTES_TESTNETS_PUBLIC: [u8; 4] = [0x04, 0x35, 0x87, 0xCF];
|
|
|
|
/// Version bytes for extended private keys on any of the testnet networks.
|
|
|
|
const VERSION_BYTES_TESTNETS_PRIVATE: [u8; 4] = [0x04, 0x35, 0x83, 0x94];
|
|
|
|
|
2023-12-07 19:11:40 +00:00
|
|
|
/// The old name for xpub, extended public key.
|
|
|
|
#[deprecated(since = "0.31.0", note = "use xpub instead")]
|
|
|
|
pub type ExtendendPubKey = Xpub;
|
|
|
|
|
|
|
|
/// The old name for xpriv, extended public key.
|
|
|
|
#[deprecated(since = "0.31.0", note = "use xpriv instead")]
|
|
|
|
pub type ExtendendPrivKey = Xpriv;
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
/// A chain code
|
2019-12-02 11:00:09 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2016-06-24 19:15:57 +00:00
|
|
|
pub struct ChainCode([u8; 32]);
|
|
|
|
impl_array_newtype!(ChainCode, u8, 32);
|
2019-07-15 17:41:59 +00:00
|
|
|
impl_bytes_newtype!(ChainCode, 32);
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2022-12-23 00:28:17 +00:00
|
|
|
impl ChainCode {
|
|
|
|
fn from_hmac(hmac: Hmac<sha512::Hash>) -> Self {
|
|
|
|
hmac[32..].try_into().expect("half of hmac is guaranteed to be 32 bytes")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
/// A fingerprint
|
2021-11-03 09:20:34 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
2016-06-24 19:15:57 +00:00
|
|
|
pub struct Fingerprint([u8; 4]);
|
|
|
|
impl_array_newtype!(Fingerprint, u8, 4);
|
2019-07-15 17:41:59 +00:00
|
|
|
impl_bytes_newtype!(Fingerprint, 4);
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2023-08-21 23:27:17 +00:00
|
|
|
hash_newtype! {
|
2023-08-22 03:41:01 +00:00
|
|
|
/// Extended key identifier as defined in BIP-32.
|
|
|
|
pub struct XKeyIdentifier(hash160::Hash);
|
2023-08-21 23:27:17 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
/// Extended private key
|
2021-04-12 11:47:03 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
|
|
#[cfg_attr(feature = "std", derive(Debug))]
|
2023-08-21 22:03:55 +00:00
|
|
|
pub struct Xpriv {
|
2016-06-24 19:15:57 +00:00
|
|
|
/// The network this key is to be used on
|
2023-11-27 23:40:08 +00:00
|
|
|
pub network: NetworkKind,
|
2016-06-24 19:15:57 +00:00
|
|
|
/// How many derivations this key is from the master (which is 0)
|
|
|
|
pub depth: u8,
|
|
|
|
/// Fingerprint of the parent key (0 for master)
|
|
|
|
pub parent_fingerprint: Fingerprint,
|
|
|
|
/// Child number of the key used to derive from parent (0 for master)
|
|
|
|
pub child_number: ChildNumber,
|
2019-02-27 01:56:50 +00:00
|
|
|
/// Private key
|
2021-04-12 11:47:03 +00:00
|
|
|
pub private_key: secp256k1::SecretKey,
|
2016-06-24 19:15:57 +00:00
|
|
|
/// Chain code
|
2022-08-24 06:16:34 +00:00
|
|
|
pub chain_code: ChainCode,
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
2022-09-20 06:07:58 +00:00
|
|
|
#[cfg(feature = "serde")]
|
2023-08-21 22:03:55 +00:00
|
|
|
crate::serde_utils::serde_string_impl!(Xpriv, "a BIP-32 extended private key");
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2021-04-12 11:47:03 +00:00
|
|
|
#[cfg(not(feature = "std"))]
|
2023-08-21 22:03:55 +00:00
|
|
|
impl fmt::Debug for Xpriv {
|
2021-04-12 11:47:03 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2023-08-21 22:03:55 +00:00
|
|
|
f.debug_struct("Xpriv")
|
2021-04-12 11:47:03 +00:00
|
|
|
.field("network", &self.network)
|
|
|
|
.field("depth", &self.depth)
|
|
|
|
.field("parent_fingerprint", &self.parent_fingerprint)
|
|
|
|
.field("child_number", &self.child_number)
|
|
|
|
.field("chain_code", &self.chain_code)
|
2022-04-25 16:14:41 +00:00
|
|
|
.field("private_key", &"[SecretKey]")
|
|
|
|
.finish()
|
2021-04-12 11:47:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
/// Extended public key
|
2020-06-03 15:44:42 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
2023-08-21 22:03:55 +00:00
|
|
|
pub struct Xpub {
|
2023-11-27 23:40:08 +00:00
|
|
|
/// The network kind this key is to be used on
|
|
|
|
pub network: NetworkKind,
|
2016-06-24 19:15:57 +00:00
|
|
|
/// How many derivations this key is from the master (which is 0)
|
|
|
|
pub depth: u8,
|
|
|
|
/// Fingerprint of the parent key
|
|
|
|
pub parent_fingerprint: Fingerprint,
|
|
|
|
/// Child number of the key used to derive from parent (0 for master)
|
|
|
|
pub child_number: ChildNumber,
|
|
|
|
/// Public key
|
2021-04-12 11:47:03 +00:00
|
|
|
pub public_key: secp256k1::PublicKey,
|
2016-06-24 19:15:57 +00:00
|
|
|
/// Chain code
|
2022-08-24 06:16:34 +00:00
|
|
|
pub chain_code: ChainCode,
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
2022-09-20 06:07:58 +00:00
|
|
|
#[cfg(feature = "serde")]
|
2023-08-21 22:03:55 +00:00
|
|
|
crate::serde_utils::serde_string_impl!(Xpub, "a BIP-32 extended public key");
|
2016-06-24 19:15:57 +00:00
|
|
|
|
|
|
|
/// A child number for a derived key
|
2020-06-03 15:44:42 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
|
2016-06-24 19:15:57 +00:00
|
|
|
pub enum ChildNumber {
|
2018-08-11 19:30:38 +00:00
|
|
|
/// Non-hardened key
|
|
|
|
Normal {
|
|
|
|
/// Key index, within [0, 2^31 - 1]
|
2022-08-24 06:16:34 +00:00
|
|
|
index: u32,
|
2018-08-11 19:30:38 +00:00
|
|
|
},
|
|
|
|
/// Hardened key
|
|
|
|
Hardened {
|
|
|
|
/// Key index, within [0, 2^31 - 1]
|
2022-08-24 06:16:34 +00:00
|
|
|
index: u32,
|
2018-08-11 19:30:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ChildNumber {
|
2019-02-14 11:05:20 +00:00
|
|
|
/// Create a [`Normal`] from an index, returns an error if the index is not within
|
2018-08-11 20:29:10 +00:00
|
|
|
/// [0, 2^31 - 1].
|
|
|
|
///
|
|
|
|
/// [`Normal`]: #variant.Normal
|
2019-02-14 11:05:20 +00:00
|
|
|
pub fn from_normal_idx(index: u32) -> Result<Self, Error> {
|
|
|
|
if index & (1 << 31) == 0 {
|
2021-11-03 09:20:34 +00:00
|
|
|
Ok(ChildNumber::Normal { index })
|
2019-02-14 11:05:20 +00:00
|
|
|
} else {
|
|
|
|
Err(Error::InvalidChildNumber(index))
|
|
|
|
}
|
2018-08-11 19:30:38 +00:00
|
|
|
}
|
|
|
|
|
2019-02-14 11:05:20 +00:00
|
|
|
/// Create a [`Hardened`] from an index, returns an error if the index is not within
|
2018-08-11 20:29:10 +00:00
|
|
|
/// [0, 2^31 - 1].
|
|
|
|
///
|
|
|
|
/// [`Hardened`]: #variant.Hardened
|
2019-02-14 11:05:20 +00:00
|
|
|
pub fn from_hardened_idx(index: u32) -> Result<Self, Error> {
|
|
|
|
if index & (1 << 31) == 0 {
|
2021-11-03 09:20:34 +00:00
|
|
|
Ok(ChildNumber::Hardened { index })
|
2019-02-14 11:05:20 +00:00
|
|
|
} else {
|
|
|
|
Err(Error::InvalidChildNumber(index))
|
|
|
|
}
|
2018-08-11 19:30:38 +00:00
|
|
|
}
|
2018-08-11 20:29:10 +00:00
|
|
|
|
|
|
|
/// Returns `true` if the child number is a [`Normal`] value.
|
|
|
|
///
|
|
|
|
/// [`Normal`]: #variant.Normal
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn is_normal(&self) -> bool { !self.is_hardened() }
|
2018-08-11 20:29:10 +00:00
|
|
|
|
|
|
|
/// Returns `true` if the child number is a [`Hardened`] value.
|
|
|
|
///
|
|
|
|
/// [`Hardened`]: #variant.Hardened
|
2020-11-28 12:49:50 +00:00
|
|
|
pub fn is_hardened(&self) -> bool {
|
2019-08-05 18:52:34 +00:00
|
|
|
match self {
|
2022-08-24 06:16:34 +00:00
|
|
|
ChildNumber::Hardened { .. } => true,
|
|
|
|
ChildNumber::Normal { .. } => false,
|
2018-08-11 20:29:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:11:10 +00:00
|
|
|
/// Returns the child number that is a single increment from this one.
|
|
|
|
pub fn increment(self) -> Result<ChildNumber, Error> {
|
|
|
|
match self {
|
2022-08-24 06:16:34 +00:00
|
|
|
ChildNumber::Normal { index: idx } => ChildNumber::from_normal_idx(idx + 1),
|
|
|
|
ChildNumber::Hardened { index: idx } => ChildNumber::from_hardened_idx(idx + 1),
|
2019-05-03 15:11:10 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-08 06:00:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u32> for ChildNumber {
|
2018-08-11 19:30:38 +00:00
|
|
|
fn from(number: u32) -> Self {
|
|
|
|
if number & (1 << 31) != 0 {
|
|
|
|
ChildNumber::Hardened { index: number ^ (1 << 31) }
|
2018-08-08 06:00:47 +00:00
|
|
|
} else {
|
2018-08-11 19:30:38 +00:00
|
|
|
ChildNumber::Normal { index: number }
|
2018-08-08 06:00:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ChildNumber> for u32 {
|
|
|
|
fn from(cnum: ChildNumber) -> Self {
|
|
|
|
match cnum {
|
2018-08-11 19:30:38 +00:00
|
|
|
ChildNumber::Normal { index } => index,
|
|
|
|
ChildNumber::Hardened { index } => index | (1 << 31),
|
2018-08-08 06:00:47 +00:00
|
|
|
}
|
|
|
|
}
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 19:45:42 +00:00
|
|
|
impl fmt::Display for ChildNumber {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match *self {
|
2021-02-06 22:41:49 +00:00
|
|
|
ChildNumber::Hardened { index } => {
|
|
|
|
fmt::Display::fmt(&index, f)?;
|
|
|
|
let alt = f.alternate();
|
2021-06-08 13:19:01 +00:00
|
|
|
f.write_str(if alt { "h" } else { "'" })
|
2022-08-24 06:16:34 +00:00
|
|
|
}
|
2021-02-06 22:41:49 +00:00
|
|
|
ChildNumber::Normal { index } => fmt::Display::fmt(&index, f),
|
2016-06-24 19:45:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
impl FromStr for ChildNumber {
|
|
|
|
type Err = Error;
|
|
|
|
|
|
|
|
fn from_str(inp: &str) -> Result<ChildNumber, Error> {
|
2019-08-05 19:41:07 +00:00
|
|
|
let is_hardened = inp.chars().last().map_or(false, |l| l == '\'' || l == 'h');
|
|
|
|
Ok(if is_hardened {
|
2022-08-24 06:16:34 +00:00
|
|
|
ChildNumber::from_hardened_idx(
|
|
|
|
inp[0..inp.len() - 1].parse().map_err(|_| Error::InvalidChildNumberFormat)?,
|
|
|
|
)?
|
2019-08-05 19:41:07 +00:00
|
|
|
} else {
|
|
|
|
ChildNumber::from_normal_idx(inp.parse().map_err(|_| Error::InvalidChildNumberFormat)?)?
|
2019-02-07 21:12:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-26 14:29:11 +00:00
|
|
|
impl AsRef<[ChildNumber]> for ChildNumber {
|
|
|
|
fn as_ref(&self) -> &[ChildNumber] { slice::from_ref(self) }
|
|
|
|
}
|
|
|
|
|
2018-08-20 16:37:19 +00:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
impl<'de> serde::Deserialize<'de> for ChildNumber {
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: serde::Deserializer<'de>,
|
|
|
|
{
|
|
|
|
u32::deserialize(deserializer).map(ChildNumber::from)
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-20 16:37:19 +00:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
impl serde::Serialize for ChildNumber {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::Serializer,
|
|
|
|
{
|
|
|
|
u32::from(*self).serialize(serializer)
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:03:28 +00:00
|
|
|
/// Trait that allows possibly failable conversion from a type into a
|
|
|
|
/// derivation path
|
|
|
|
pub trait IntoDerivationPath {
|
2024-03-03 05:41:23 +00:00
|
|
|
/// Converts a given type into a [`DerivationPath`] with possible error
|
2020-09-26 19:03:28 +00:00
|
|
|
fn into_derivation_path(self) -> Result<DerivationPath, Error>;
|
|
|
|
}
|
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
/// A BIP-32 derivation path.
|
2020-06-03 15:44:42 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
2019-02-11 22:59:25 +00:00
|
|
|
pub struct DerivationPath(Vec<ChildNumber>);
|
2022-09-20 06:07:58 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
crate::serde_utils::serde_string_impl!(DerivationPath, "a BIP-32 derivation path");
|
2019-02-07 21:12:43 +00:00
|
|
|
|
2022-01-21 01:50:01 +00:00
|
|
|
impl<I> Index<I> for DerivationPath
|
|
|
|
where
|
|
|
|
Vec<ChildNumber>: Index<I>,
|
|
|
|
{
|
|
|
|
type Output = <Vec<ChildNumber> as Index<I>>::Output;
|
|
|
|
|
|
|
|
#[inline]
|
2022-08-24 06:16:34 +00:00
|
|
|
fn index(&self, index: I) -> &Self::Output { &self.0[index] }
|
2022-01-21 01:50:01 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:03:28 +00:00
|
|
|
impl Default for DerivationPath {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn default() -> DerivationPath { DerivationPath::master() }
|
2020-09-26 19:03:28 +00:00
|
|
|
}
|
|
|
|
|
2022-08-24 06:16:34 +00:00
|
|
|
impl<T> IntoDerivationPath for T
|
|
|
|
where
|
|
|
|
T: Into<DerivationPath>,
|
|
|
|
{
|
|
|
|
fn into_derivation_path(self) -> Result<DerivationPath, Error> { Ok(self.into()) }
|
2020-09-26 19:03:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-14 14:04:18 +00:00
|
|
|
impl IntoDerivationPath for String {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn into_derivation_path(self) -> Result<DerivationPath, Error> { self.parse() }
|
2020-10-14 14:04:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> IntoDerivationPath for &'a str {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn into_derivation_path(self) -> Result<DerivationPath, Error> { self.parse() }
|
2020-10-14 14:04:18 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
impl From<Vec<ChildNumber>> for DerivationPath {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn from(numbers: Vec<ChildNumber>) -> Self { DerivationPath(numbers) }
|
2019-02-07 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 03:19:17 +00:00
|
|
|
impl From<DerivationPath> for Vec<ChildNumber> {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn from(path: DerivationPath) -> Self { path.0 }
|
2019-02-07 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2019-02-11 22:59:25 +00:00
|
|
|
impl<'a> From<&'a [ChildNumber]> for DerivationPath {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn from(numbers: &'a [ChildNumber]) -> Self { DerivationPath(numbers.to_vec()) }
|
2019-02-11 22:59:25 +00:00
|
|
|
}
|
|
|
|
|
2022-06-01 22:08:56 +00:00
|
|
|
impl core::iter::FromIterator<ChildNumber> for DerivationPath {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn from_iter<T>(iter: T) -> Self
|
|
|
|
where
|
|
|
|
T: IntoIterator<Item = ChildNumber>,
|
|
|
|
{
|
2019-02-11 22:59:25 +00:00
|
|
|
DerivationPath(Vec::from_iter(iter))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-01 22:08:56 +00:00
|
|
|
impl<'a> core::iter::IntoIterator for &'a DerivationPath {
|
2019-02-11 22:59:25 +00:00
|
|
|
type Item = &'a ChildNumber;
|
2021-06-09 10:34:44 +00:00
|
|
|
type IntoIter = slice::Iter<'a, ChildNumber>;
|
2022-08-24 06:16:34 +00:00
|
|
|
fn into_iter(self) -> Self::IntoIter { self.0.iter() }
|
2019-02-11 22:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<[ChildNumber]> for DerivationPath {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn as_ref(&self) -> &[ChildNumber] { &self.0 }
|
2019-02-11 22:59:25 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
impl FromStr for DerivationPath {
|
|
|
|
type Err = Error;
|
|
|
|
|
|
|
|
fn from_str(path: &str) -> Result<DerivationPath, Error> {
|
2024-04-10 21:20:58 +00:00
|
|
|
if path.is_empty() || path == "m" || path == "m/" {
|
|
|
|
return Ok(vec![].into());
|
|
|
|
}
|
|
|
|
|
|
|
|
let path = path.strip_prefix("m/").unwrap_or(path);
|
|
|
|
|
|
|
|
let parts = path.split('/');
|
|
|
|
let ret: Result<Vec<ChildNumber>, Error> = parts.map(str::parse).collect();
|
2019-02-07 21:12:43 +00:00
|
|
|
Ok(DerivationPath(ret?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:11:10 +00:00
|
|
|
/// An iterator over children of a [DerivationPath].
|
|
|
|
///
|
2021-05-03 09:41:58 +00:00
|
|
|
/// It is returned by the methods [DerivationPath::children_from],
|
2019-05-03 15:11:10 +00:00
|
|
|
/// [DerivationPath::normal_children] and [DerivationPath::hardened_children].
|
|
|
|
pub struct DerivationPathIterator<'a> {
|
|
|
|
base: &'a DerivationPath,
|
|
|
|
next_child: Option<ChildNumber>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> DerivationPathIterator<'a> {
|
|
|
|
/// Start a new [DerivationPathIterator] at the given child.
|
|
|
|
pub fn start_from(path: &'a DerivationPath, start: ChildNumber) -> DerivationPathIterator<'a> {
|
2022-08-24 06:16:34 +00:00
|
|
|
DerivationPathIterator { base: path, next_child: Some(start) }
|
2019-05-03 15:11:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for DerivationPathIterator<'a> {
|
|
|
|
type Item = DerivationPath;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
2019-08-05 19:41:07 +00:00
|
|
|
let ret = self.next_child?;
|
2019-05-03 15:11:10 +00:00
|
|
|
self.next_child = ret.increment().ok();
|
|
|
|
Some(self.base.child(ret))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-11 22:59:25 +00:00
|
|
|
impl DerivationPath {
|
2020-11-28 12:49:50 +00:00
|
|
|
/// Returns length of the derivation path
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn len(&self) -> usize { self.0.len() }
|
2020-11-28 12:49:50 +00:00
|
|
|
|
2021-11-03 09:20:34 +00:00
|
|
|
/// Returns `true` if the derivation path is empty
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn is_empty(&self) -> bool { self.0.is_empty() }
|
2021-11-03 09:20:34 +00:00
|
|
|
|
2020-09-26 19:03:28 +00:00
|
|
|
/// Returns derivation path for a master key (i.e. empty derivation path)
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn master() -> DerivationPath { DerivationPath(vec![]) }
|
2020-09-26 19:03:28 +00:00
|
|
|
|
|
|
|
/// Returns whether derivation path represents master key (i.e. it's length
|
|
|
|
/// is empty). True for `m` path.
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn is_master(&self) -> bool { self.0.is_empty() }
|
2020-09-26 19:03:28 +00:00
|
|
|
|
2019-05-03 15:11:10 +00:00
|
|
|
/// Create a new [DerivationPath] that is a child of this one.
|
2019-02-11 22:59:25 +00:00
|
|
|
pub fn child(&self, cn: ChildNumber) -> DerivationPath {
|
|
|
|
let mut path = self.0.clone();
|
|
|
|
path.push(cn);
|
|
|
|
DerivationPath(path)
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:11:10 +00:00
|
|
|
/// Convert into a [DerivationPath] that is a child of this one.
|
2019-02-11 22:59:25 +00:00
|
|
|
pub fn into_child(self, cn: ChildNumber) -> DerivationPath {
|
|
|
|
let mut path = self.0;
|
|
|
|
path.push(cn);
|
|
|
|
DerivationPath(path)
|
|
|
|
}
|
2019-05-03 15:11:10 +00:00
|
|
|
|
|
|
|
/// Get an [Iterator] over the children of this [DerivationPath]
|
|
|
|
/// starting with the given [ChildNumber].
|
|
|
|
pub fn children_from(&self, cn: ChildNumber) -> DerivationPathIterator {
|
2021-11-03 09:20:34 +00:00
|
|
|
DerivationPathIterator::start_from(self, cn)
|
2019-05-03 15:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get an [Iterator] over the unhardened children of this [DerivationPath].
|
|
|
|
pub fn normal_children(&self) -> DerivationPathIterator {
|
2022-08-24 06:16:34 +00:00
|
|
|
DerivationPathIterator::start_from(self, ChildNumber::Normal { index: 0 })
|
2019-05-03 15:11:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get an [Iterator] over the hardened children of this [DerivationPath].
|
|
|
|
pub fn hardened_children(&self) -> DerivationPathIterator {
|
2022-08-24 06:16:34 +00:00
|
|
|
DerivationPathIterator::start_from(self, ChildNumber::Hardened { index: 0 })
|
2019-05-03 15:11:10 +00:00
|
|
|
}
|
2020-08-19 14:08:09 +00:00
|
|
|
|
|
|
|
/// Concatenate `self` with `path` and return the resulting new path.
|
|
|
|
///
|
|
|
|
/// ```
|
2022-10-20 20:28:23 +00:00
|
|
|
/// use bitcoin::bip32::{DerivationPath, ChildNumber};
|
2020-08-19 14:08:09 +00:00
|
|
|
/// use std::str::FromStr;
|
|
|
|
///
|
2024-04-10 21:20:58 +00:00
|
|
|
/// let base = DerivationPath::from_str("m/42").unwrap();
|
2020-08-19 14:08:09 +00:00
|
|
|
///
|
2024-02-05 16:29:31 +00:00
|
|
|
/// let deriv_1 = base.extend(DerivationPath::from_str("0/1").unwrap());
|
2020-08-19 14:08:09 +00:00
|
|
|
/// let deriv_2 = base.extend(&[
|
|
|
|
/// ChildNumber::from_normal_idx(0).unwrap(),
|
|
|
|
/// ChildNumber::from_normal_idx(1).unwrap()
|
|
|
|
/// ]);
|
|
|
|
///
|
|
|
|
/// assert_eq!(deriv_1, deriv_2);
|
|
|
|
/// ```
|
|
|
|
pub fn extend<T: AsRef<[ChildNumber]>>(&self, path: T) -> DerivationPath {
|
|
|
|
let mut new_path = self.clone();
|
|
|
|
new_path.0.extend_from_slice(path.as_ref());
|
|
|
|
new_path
|
|
|
|
}
|
2023-07-18 12:16:24 +00:00
|
|
|
|
|
|
|
/// Returns the derivation path as a vector of u32 integers.
|
|
|
|
/// Unhardened elements are copied as is.
|
|
|
|
/// 0x80000000 is added to the hardened elements.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bitcoin::bip32::DerivationPath;
|
|
|
|
/// use std::str::FromStr;
|
|
|
|
///
|
2024-04-10 21:20:58 +00:00
|
|
|
/// let path = DerivationPath::from_str("m/84'/0'/0'/0/1").unwrap();
|
2023-07-18 12:16:24 +00:00
|
|
|
/// const HARDENED: u32 = 0x80000000;
|
|
|
|
/// assert_eq!(path.to_u32_vec(), vec![84 + HARDENED, HARDENED, HARDENED, 0, 1]);
|
|
|
|
/// ```
|
|
|
|
pub fn to_u32_vec(&self) -> Vec<u32> { self.into_iter().map(|&el| el.into()).collect() }
|
2019-02-11 22:59:25 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
impl fmt::Display for DerivationPath {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2024-02-05 16:29:31 +00:00
|
|
|
let mut iter = self.0.iter();
|
|
|
|
if let Some(first_element) = iter.next() {
|
|
|
|
write!(f, "{}", first_element)?;
|
|
|
|
}
|
|
|
|
for cn in iter {
|
2019-02-07 21:12:43 +00:00
|
|
|
f.write_str("/")?;
|
2024-02-05 16:29:31 +00:00
|
|
|
write!(f, "{}", cn)?;
|
2019-02-07 21:12:43 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for DerivationPath {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self, f) }
|
2019-02-07 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2020-09-13 20:49:52 +00:00
|
|
|
/// Full information on the used extended public key: fingerprint of the
|
|
|
|
/// master extended public key and a derivation path from it.
|
2020-09-13 22:37:29 +00:00
|
|
|
pub type KeySource = (Fingerprint, DerivationPath);
|
2020-09-13 20:49:52 +00:00
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
/// A BIP32 error
|
2023-07-27 01:10:22 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2022-05-31 04:29:50 +00:00
|
|
|
#[non_exhaustive]
|
2016-06-24 19:15:57 +00:00
|
|
|
pub enum Error {
|
|
|
|
/// A pk->pk derivation was attempted on a hardened key
|
|
|
|
CannotDeriveFromHardenedKey,
|
2019-01-23 18:30:32 +00:00
|
|
|
/// A secp256k1 error occurred
|
2021-01-30 13:32:44 +00:00
|
|
|
Secp256k1(secp256k1::Error),
|
2016-06-24 19:15:57 +00:00
|
|
|
/// A child number was provided that was out of range
|
2019-02-14 11:05:20 +00:00
|
|
|
InvalidChildNumber(u32),
|
2019-02-07 21:12:43 +00:00
|
|
|
/// Invalid childnumber format.
|
|
|
|
InvalidChildNumberFormat,
|
|
|
|
/// Invalid derivation path format.
|
|
|
|
InvalidDerivationPathFormat,
|
2020-09-10 00:37:10 +00:00
|
|
|
/// Unknown version magic bytes
|
|
|
|
UnknownVersion([u8; 4]),
|
2020-11-10 08:34:29 +00:00
|
|
|
/// Encoded extended key data has wrong length
|
2020-09-10 00:37:10 +00:00
|
|
|
WrongExtendedKeyLength(usize),
|
|
|
|
/// Base58 encoding error
|
2022-02-13 08:06:51 +00:00
|
|
|
Base58(base58::Error),
|
|
|
|
/// Hexadecimal decoding error
|
2023-07-21 00:38:34 +00:00
|
|
|
Hex(hex::HexToArrayError),
|
2023-01-23 03:49:09 +00:00
|
|
|
/// `PublicKey` hex should be 66 or 130 digits long.
|
|
|
|
InvalidPublicKeyHexLength(usize),
|
2024-02-15 05:26:55 +00:00
|
|
|
/// Base58 decoded data was an invalid length.
|
2024-03-31 01:03:18 +00:00
|
|
|
InvalidBase58PayloadLength(InvalidBase58PayloadLengthError),
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 23:21:50 +00:00
|
|
|
internals::impl_from_infallible!(Error);
|
|
|
|
|
2016-06-24 19:45:42 +00:00
|
|
|
impl fmt::Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
use Error::*;
|
|
|
|
|
2016-06-24 19:45:42 +00:00
|
|
|
match *self {
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
CannotDeriveFromHardenedKey =>
|
2022-08-24 06:16:34 +00:00
|
|
|
f.write_str("cannot derive hardened key from public key"),
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
|
|
|
|
InvalidChildNumber(ref n) =>
|
2022-08-24 06:16:34 +00:00
|
|
|
write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
InvalidChildNumberFormat => f.write_str("invalid child number format"),
|
|
|
|
InvalidDerivationPathFormat => f.write_str("invalid derivation path format"),
|
|
|
|
UnknownVersion(ref bytes) => write!(f, "unknown version magic bytes: {:?}", bytes),
|
|
|
|
WrongExtendedKeyLength(ref len) =>
|
2022-08-24 06:16:34 +00:00
|
|
|
write!(f, "encoded extended key data has wrong length {}", len),
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
Base58(ref e) => write_err!(f, "base58 encoding error"; e),
|
|
|
|
Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e),
|
|
|
|
InvalidPublicKeyHexLength(got) =>
|
2022-11-02 22:36:37 +00:00
|
|
|
write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got),
|
2024-02-15 05:26:55 +00:00
|
|
|
InvalidBase58PayloadLength(ref e) => write_err!(f, "base58 payload"; e),
|
2016-06-24 19:45:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-09 10:34:44 +00:00
|
|
|
#[cfg(feature = "std")]
|
2022-05-04 05:56:24 +00:00
|
|
|
impl std::error::Error for Error {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
use Error::*;
|
2022-05-04 05:56:24 +00:00
|
|
|
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
match *self {
|
|
|
|
Secp256k1(ref e) => Some(e),
|
|
|
|
Base58(ref e) => Some(e),
|
|
|
|
Hex(ref e) => Some(e),
|
2024-02-15 05:26:55 +00:00
|
|
|
InvalidBase58PayloadLength(ref e) => Some(e),
|
2022-05-04 05:56:24 +00:00
|
|
|
CannotDeriveFromHardenedKey
|
|
|
|
| InvalidChildNumber(_)
|
|
|
|
| InvalidChildNumberFormat
|
|
|
|
| InvalidDerivationPathFormat
|
|
|
|
| UnknownVersion(_)
|
2023-01-23 03:49:09 +00:00
|
|
|
| WrongExtendedKeyLength(_)
|
|
|
|
| InvalidPublicKeyHexLength(_) => None,
|
2022-01-24 01:36:46 +00:00
|
|
|
}
|
2016-06-24 19:45:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:25:47 +00:00
|
|
|
impl From<secp256k1::Error> for Error {
|
2021-01-30 13:32:44 +00:00
|
|
|
fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
|
2016-06-24 19:25:47 +00:00
|
|
|
}
|
|
|
|
|
2020-09-10 00:37:10 +00:00
|
|
|
impl From<base58::Error> for Error {
|
2022-08-24 06:16:34 +00:00
|
|
|
fn from(err: base58::Error) -> Self { Error::Base58(err) }
|
2020-09-10 00:37:10 +00:00
|
|
|
}
|
|
|
|
|
2024-02-15 05:26:55 +00:00
|
|
|
impl From<InvalidBase58PayloadLengthError> for Error {
|
|
|
|
fn from(e: InvalidBase58PayloadLengthError) -> Error { Self::InvalidBase58PayloadLength(e) }
|
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
impl Xpriv {
|
2016-06-24 19:15:57 +00:00
|
|
|
/// Construct a new master key from a seed value
|
2023-11-27 23:40:08 +00:00
|
|
|
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Result<Xpriv, Error> {
|
2019-01-16 20:45:31 +00:00
|
|
|
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(b"Bitcoin seed");
|
|
|
|
hmac_engine.input(seed);
|
|
|
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Ok(Xpriv {
|
2023-11-27 23:40:08 +00:00
|
|
|
network: network.into(),
|
2016-06-24 19:15:57 +00:00
|
|
|
depth: 0,
|
|
|
|
parent_fingerprint: Default::default(),
|
2019-02-14 11:05:20 +00:00
|
|
|
child_number: ChildNumber::from_normal_idx(0)?,
|
2021-04-12 11:47:03 +00:00
|
|
|
private_key: secp256k1::SecretKey::from_slice(&hmac_result[..32])?,
|
2022-12-23 00:28:17 +00:00
|
|
|
chain_code: ChainCode::from_hmac(hmac_result),
|
2016-06-24 19:15:57 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-01 19:03:58 +00:00
|
|
|
/// Constructs ECDSA compressed private key matching internal secret key representation.
|
2022-08-01 22:33:22 +00:00
|
|
|
pub fn to_priv(self) -> PrivateKey {
|
2023-11-27 23:40:08 +00:00
|
|
|
PrivateKey { compressed: true, network: self.network, inner: self.private_key }
|
2021-08-01 19:03:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs BIP340 keypair for Schnorr signatures and Taproot use matching the internal
|
|
|
|
/// secret key representation.
|
2023-10-02 01:48:50 +00:00
|
|
|
pub fn to_keypair<C: secp256k1::Signing>(self, secp: &Secp256k1<C>) -> Keypair {
|
|
|
|
Keypair::from_seckey_slice(secp, &self.private_key[..])
|
2022-08-24 06:16:34 +00:00
|
|
|
.expect("BIP32 internal private key representation is broken")
|
2021-08-01 19:03:58 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 00:01:14 +00:00
|
|
|
/// Attempts to derive an extended private key from a path.
|
2019-02-11 22:59:25 +00:00
|
|
|
///
|
|
|
|
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
|
|
|
|
pub fn derive_priv<C: secp256k1::Signing, P: AsRef<[ChildNumber]>>(
|
2018-08-13 00:01:14 +00:00
|
|
|
&self,
|
2018-07-27 20:15:48 +00:00
|
|
|
secp: &Secp256k1<C>,
|
2019-02-11 22:59:25 +00:00
|
|
|
path: &P,
|
2023-08-21 22:03:55 +00:00
|
|
|
) -> Result<Xpriv, Error> {
|
|
|
|
let mut sk: Xpriv = *self;
|
2019-02-11 22:59:25 +00:00
|
|
|
for cnum in path.as_ref() {
|
2018-08-13 00:01:14 +00:00
|
|
|
sk = sk.ckd_priv(secp, *cnum)?;
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
Ok(sk)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Private->Private child key derivation
|
2023-05-26 14:29:11 +00:00
|
|
|
fn ckd_priv<C: secp256k1::Signing>(
|
2022-08-24 06:16:34 +00:00
|
|
|
&self,
|
|
|
|
secp: &Secp256k1<C>,
|
|
|
|
i: ChildNumber,
|
2023-08-21 22:03:55 +00:00
|
|
|
) -> Result<Xpriv, Error> {
|
2019-01-16 20:45:31 +00:00
|
|
|
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
|
2016-06-24 19:15:57 +00:00
|
|
|
match i {
|
2020-09-10 00:37:10 +00:00
|
|
|
ChildNumber::Normal { .. } => {
|
2016-06-24 19:15:57 +00:00
|
|
|
// Non-hardened key: compute public data and use that
|
2022-08-24 06:16:34 +00:00
|
|
|
hmac_engine.input(
|
|
|
|
&secp256k1::PublicKey::from_secret_key(secp, &self.private_key).serialize()[..],
|
|
|
|
);
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
2020-09-10 00:37:10 +00:00
|
|
|
ChildNumber::Hardened { .. } => {
|
2016-06-24 19:15:57 +00:00
|
|
|
// Hardened key: use only secret data to prevent public derivation
|
2019-01-16 20:45:31 +00:00
|
|
|
hmac_engine.input(&[0u8]);
|
2019-02-27 01:56:50 +00:00
|
|
|
hmac_engine.input(&self.private_key[..]);
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-11 19:30:38 +00:00
|
|
|
|
2022-08-31 04:45:14 +00:00
|
|
|
hmac_engine.input(&u32::from(i).to_be_bytes());
|
2019-01-16 20:45:31 +00:00
|
|
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
2022-08-24 06:16:34 +00:00
|
|
|
let sk = secp256k1::SecretKey::from_slice(&hmac_result[..32])
|
|
|
|
.expect("statistically impossible to hit");
|
|
|
|
let tweaked =
|
|
|
|
sk.add_tweak(&self.private_key.into()).expect("statistically impossible to hit");
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Ok(Xpriv {
|
2016-06-24 19:15:57 +00:00
|
|
|
network: self.network,
|
|
|
|
depth: self.depth + 1,
|
|
|
|
parent_fingerprint: self.fingerprint(secp),
|
|
|
|
child_number: i,
|
2022-06-28 02:47:29 +00:00
|
|
|
private_key: tweaked,
|
2022-12-23 00:28:17 +00:00
|
|
|
chain_code: ChainCode::from_hmac(hmac_result),
|
2016-06-24 19:15:57 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-10 00:37:10 +00:00
|
|
|
/// Decoding extended private key from binary data according to BIP 32
|
2023-08-21 22:03:55 +00:00
|
|
|
pub fn decode(data: &[u8]) -> Result<Xpriv, Error> {
|
2020-09-10 00:37:10 +00:00
|
|
|
if data.len() != 78 {
|
2022-08-24 06:16:34 +00:00
|
|
|
return Err(Error::WrongExtendedKeyLength(data.len()));
|
2020-09-10 00:37:10 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 23:20:49 +00:00
|
|
|
let network = if data.starts_with(&VERSION_BYTES_MAINNET_PRIVATE) {
|
2023-11-27 23:40:08 +00:00
|
|
|
NetworkKind::Main
|
2023-08-21 23:20:49 +00:00
|
|
|
} else if data.starts_with(&VERSION_BYTES_TESTNETS_PRIVATE) {
|
2023-11-27 23:40:08 +00:00
|
|
|
NetworkKind::Test
|
2023-08-21 23:20:49 +00:00
|
|
|
} else {
|
|
|
|
let (b0, b1, b2, b3) = (data[0], data[1], data[2], data[3]);
|
|
|
|
return Err(Error::UnknownVersion([b0, b1, b2, b3]));
|
2020-09-10 00:37:10 +00:00
|
|
|
};
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Ok(Xpriv {
|
2021-11-03 09:20:34 +00:00
|
|
|
network,
|
2020-09-10 00:37:10 +00:00
|
|
|
depth: data[4],
|
2022-11-02 22:36:37 +00:00
|
|
|
parent_fingerprint: data[5..9]
|
|
|
|
.try_into()
|
|
|
|
.expect("9 - 5 == 4, which is the Fingerprint length"),
|
2022-08-31 04:45:14 +00:00
|
|
|
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
|
2022-11-02 22:36:37 +00:00
|
|
|
chain_code: data[13..45]
|
|
|
|
.try_into()
|
|
|
|
.expect("45 - 13 == 32, which is the ChainCode length"),
|
2021-04-12 11:47:03 +00:00
|
|
|
private_key: secp256k1::SecretKey::from_slice(&data[46..78])?,
|
2020-09-10 00:37:10 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extended private key binary encoding according to BIP 32
|
|
|
|
pub fn encode(&self) -> [u8; 78] {
|
|
|
|
let mut ret = [0; 78];
|
2023-08-21 23:20:49 +00:00
|
|
|
ret[0..4].copy_from_slice(&match self.network {
|
2023-11-27 23:40:08 +00:00
|
|
|
NetworkKind::Main => VERSION_BYTES_MAINNET_PRIVATE,
|
|
|
|
NetworkKind::Test => VERSION_BYTES_TESTNETS_PRIVATE,
|
2023-08-21 23:20:49 +00:00
|
|
|
});
|
2022-11-04 00:44:23 +00:00
|
|
|
ret[4] = self.depth;
|
2020-09-10 00:37:10 +00:00
|
|
|
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
|
2022-08-31 04:45:14 +00:00
|
|
|
ret[9..13].copy_from_slice(&u32::from(self.child_number).to_be_bytes());
|
2020-09-10 00:37:10 +00:00
|
|
|
ret[13..45].copy_from_slice(&self.chain_code[..]);
|
|
|
|
ret[45] = 0;
|
|
|
|
ret[46..78].copy_from_slice(&self.private_key[..]);
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
2020-10-07 14:50:27 +00:00
|
|
|
/// Returns the HASH160 of the public key belonging to the xpriv
|
2023-08-22 03:41:01 +00:00
|
|
|
pub fn identifier<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> XKeyIdentifier {
|
2023-08-21 22:03:55 +00:00
|
|
|
Xpub::from_priv(secp, self).identifier()
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the first four bytes of the identifier
|
2018-07-27 20:15:48 +00:00
|
|
|
pub fn fingerprint<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> Fingerprint {
|
2022-12-23 00:28:17 +00:00
|
|
|
self.identifier(secp)[0..4].try_into().expect("4 is the fingerprint length")
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
impl Xpub {
|
2021-08-01 19:03:58 +00:00
|
|
|
/// Derives a public key from a private key
|
2023-08-21 22:03:55 +00:00
|
|
|
pub fn from_priv<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &Xpriv) -> Xpub {
|
|
|
|
Xpub {
|
2016-06-24 19:15:57 +00:00
|
|
|
network: sk.network,
|
|
|
|
depth: sk.depth,
|
|
|
|
parent_fingerprint: sk.parent_fingerprint,
|
|
|
|
child_number: sk.child_number,
|
2021-04-12 11:47:03 +00:00
|
|
|
public_key: secp256k1::PublicKey::from_secret_key(secp, &sk.private_key),
|
2022-08-24 06:16:34 +00:00
|
|
|
chain_code: sk.chain_code,
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-01 19:03:58 +00:00
|
|
|
/// Constructs ECDSA compressed public key matching internal public key representation.
|
2023-12-11 20:10:32 +00:00
|
|
|
pub fn to_pub(self) -> CompressedPublicKey { CompressedPublicKey(self.public_key) }
|
2021-08-01 19:03:58 +00:00
|
|
|
|
|
|
|
/// Constructs BIP340 x-only public key for BIP-340 signatures and Taproot use matching
|
|
|
|
/// the internal public key representation.
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn to_x_only_pub(self) -> XOnlyPublicKey { XOnlyPublicKey::from(self.public_key) }
|
2021-08-01 19:03:58 +00:00
|
|
|
|
2018-08-13 00:01:14 +00:00
|
|
|
/// Attempts to derive an extended public key from a path.
|
2019-02-11 22:59:25 +00:00
|
|
|
///
|
2023-02-21 19:58:22 +00:00
|
|
|
/// The `path` argument can be any type implementing `AsRef<ChildNumber>`, such as `DerivationPath`, for instance.
|
2019-02-11 22:59:25 +00:00
|
|
|
pub fn derive_pub<C: secp256k1::Verification, P: AsRef<[ChildNumber]>>(
|
2018-08-13 00:01:14 +00:00
|
|
|
&self,
|
2018-07-27 20:15:48 +00:00
|
|
|
secp: &Secp256k1<C>,
|
2019-02-11 22:59:25 +00:00
|
|
|
path: &P,
|
2023-08-21 22:03:55 +00:00
|
|
|
) -> Result<Xpub, Error> {
|
|
|
|
let mut pk: Xpub = *self;
|
2019-02-11 22:59:25 +00:00
|
|
|
for cnum in path.as_ref() {
|
2018-08-13 00:01:14 +00:00
|
|
|
pk = pk.ckd_pub(secp, *cnum)?
|
|
|
|
}
|
|
|
|
Ok(pk)
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:25:47 +00:00
|
|
|
/// Compute the scalar tweak added to this key to get a child key
|
2022-08-24 06:16:34 +00:00
|
|
|
pub fn ckd_pub_tweak(
|
|
|
|
&self,
|
|
|
|
i: ChildNumber,
|
|
|
|
) -> Result<(secp256k1::SecretKey, ChainCode), Error> {
|
2016-06-24 19:15:57 +00:00
|
|
|
match i {
|
2022-08-24 06:16:34 +00:00
|
|
|
ChildNumber::Hardened { .. } => Err(Error::CannotDeriveFromHardenedKey),
|
2018-08-11 19:30:38 +00:00
|
|
|
ChildNumber::Normal { index: n } => {
|
2022-08-24 06:16:34 +00:00
|
|
|
let mut hmac_engine: HmacEngine<sha512::Hash> =
|
|
|
|
HmacEngine::new(&self.chain_code[..]);
|
2021-04-12 11:47:03 +00:00
|
|
|
hmac_engine.input(&self.public_key.serialize()[..]);
|
2022-08-31 04:45:14 +00:00
|
|
|
hmac_engine.input(&n.to_be_bytes());
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2019-01-16 20:45:31 +00:00
|
|
|
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2021-04-12 11:47:03 +00:00
|
|
|
let private_key = secp256k1::SecretKey::from_slice(&hmac_result[..32])?;
|
2022-12-23 00:28:17 +00:00
|
|
|
let chain_code = ChainCode::from_hmac(hmac_result);
|
2019-02-27 01:56:50 +00:00
|
|
|
Ok((private_key, chain_code))
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:25:47 +00:00
|
|
|
/// Public->Public child key derivation
|
2018-07-27 20:15:48 +00:00
|
|
|
pub fn ckd_pub<C: secp256k1::Verification>(
|
|
|
|
&self,
|
|
|
|
secp: &Secp256k1<C>,
|
|
|
|
i: ChildNumber,
|
2023-08-21 22:03:55 +00:00
|
|
|
) -> Result<Xpub, Error> {
|
2019-01-15 17:05:41 +00:00
|
|
|
let (sk, chain_code) = self.ckd_pub_tweak(i)?;
|
2022-06-28 02:47:29 +00:00
|
|
|
let tweaked = self.public_key.add_exp_tweak(secp, &sk.into())?;
|
2016-06-24 19:25:47 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Ok(Xpub {
|
2016-06-24 19:25:47 +00:00
|
|
|
network: self.network,
|
|
|
|
depth: self.depth + 1,
|
|
|
|
parent_fingerprint: self.fingerprint(),
|
|
|
|
child_number: i,
|
2022-06-28 02:47:29 +00:00
|
|
|
public_key: tweaked,
|
2021-11-03 09:20:34 +00:00
|
|
|
chain_code,
|
2016-06-24 19:25:47 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-10 00:37:10 +00:00
|
|
|
/// Decoding extended public key from binary data according to BIP 32
|
2023-08-21 22:03:55 +00:00
|
|
|
pub fn decode(data: &[u8]) -> Result<Xpub, Error> {
|
2020-09-10 00:37:10 +00:00
|
|
|
if data.len() != 78 {
|
2022-08-24 06:16:34 +00:00
|
|
|
return Err(Error::WrongExtendedKeyLength(data.len()));
|
2020-09-10 00:37:10 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 23:20:49 +00:00
|
|
|
let network = if data.starts_with(&VERSION_BYTES_MAINNET_PUBLIC) {
|
2023-11-27 23:40:08 +00:00
|
|
|
NetworkKind::Main
|
2023-08-21 23:20:49 +00:00
|
|
|
} else if data.starts_with(&VERSION_BYTES_TESTNETS_PUBLIC) {
|
2023-11-27 23:40:08 +00:00
|
|
|
NetworkKind::Test
|
2023-08-21 23:20:49 +00:00
|
|
|
} else {
|
|
|
|
let (b0, b1, b2, b3) = (data[0], data[1], data[2], data[3]);
|
|
|
|
return Err(Error::UnknownVersion([b0, b1, b2, b3]));
|
2023-04-01 22:55:22 +00:00
|
|
|
};
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Ok(Xpub {
|
2023-04-01 22:55:22 +00:00
|
|
|
network,
|
2020-09-10 00:37:10 +00:00
|
|
|
depth: data[4],
|
2022-11-02 22:36:37 +00:00
|
|
|
parent_fingerprint: data[5..9]
|
|
|
|
.try_into()
|
|
|
|
.expect("9 - 5 == 4, which is the Fingerprint length"),
|
2022-08-31 04:45:14 +00:00
|
|
|
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
|
2022-11-02 22:36:37 +00:00
|
|
|
chain_code: data[13..45]
|
|
|
|
.try_into()
|
|
|
|
.expect("45 - 13 == 32, which is the ChainCode length"),
|
2021-04-12 11:47:03 +00:00
|
|
|
public_key: secp256k1::PublicKey::from_slice(&data[45..78])?,
|
2020-09-10 00:37:10 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extended public key binary encoding according to BIP 32
|
|
|
|
pub fn encode(&self) -> [u8; 78] {
|
|
|
|
let mut ret = [0; 78];
|
2023-08-21 23:20:49 +00:00
|
|
|
ret[0..4].copy_from_slice(&match self.network {
|
2023-11-27 23:40:08 +00:00
|
|
|
NetworkKind::Main => VERSION_BYTES_MAINNET_PUBLIC,
|
|
|
|
NetworkKind::Test => VERSION_BYTES_TESTNETS_PUBLIC,
|
2023-08-21 23:20:49 +00:00
|
|
|
});
|
2022-11-04 00:44:23 +00:00
|
|
|
ret[4] = self.depth;
|
2020-09-10 00:37:10 +00:00
|
|
|
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
|
2022-08-31 04:45:14 +00:00
|
|
|
ret[9..13].copy_from_slice(&u32::from(self.child_number).to_be_bytes());
|
2020-09-10 00:37:10 +00:00
|
|
|
ret[13..45].copy_from_slice(&self.chain_code[..]);
|
2021-04-12 11:47:03 +00:00
|
|
|
ret[45..78].copy_from_slice(&self.public_key.serialize()[..]);
|
2020-09-10 00:37:10 +00:00
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the HASH160 of the chaincode
|
2023-08-22 03:41:01 +00:00
|
|
|
pub fn identifier(&self) -> XKeyIdentifier {
|
|
|
|
let mut engine = XKeyIdentifier::engine();
|
2022-01-25 13:50:06 +00:00
|
|
|
engine.write_all(&self.public_key.serialize()).expect("engines don't error");
|
2023-08-22 03:41:01 +00:00
|
|
|
XKeyIdentifier::from_engine(engine)
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the first four bytes of the identifier
|
2022-11-02 22:36:37 +00:00
|
|
|
pub fn fingerprint(&self) -> Fingerprint {
|
|
|
|
self.identifier()[0..4].try_into().expect("4 is the fingerprint length")
|
|
|
|
}
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
impl fmt::Display for Xpriv {
|
2018-08-08 23:11:16 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
2022-09-13 01:40:49 +00:00
|
|
|
base58::encode_check_to_fmt(fmt, &self.encode()[..])
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
impl FromStr for Xpriv {
|
2020-11-06 19:53:03 +00:00
|
|
|
type Err = Error;
|
2018-03-09 17:53:20 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
fn from_str(inp: &str) -> Result<Xpriv, Error> {
|
2022-09-13 01:40:49 +00:00
|
|
|
let data = base58::decode_check(inp)?;
|
2016-06-24 19:15:57 +00:00
|
|
|
|
|
|
|
if data.len() != 78 {
|
2024-02-15 05:26:55 +00:00
|
|
|
return Err(InvalidBase58PayloadLengthError { length: data.len() }.into());
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Xpriv::decode(&data)
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
impl fmt::Display for Xpub {
|
2018-08-08 23:11:16 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
2022-09-13 01:40:49 +00:00
|
|
|
base58::encode_check_to_fmt(fmt, &self.encode()[..])
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
impl FromStr for Xpub {
|
2020-11-06 19:53:03 +00:00
|
|
|
type Err = Error;
|
2018-03-09 17:53:20 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
fn from_str(inp: &str) -> Result<Xpub, Error> {
|
2022-09-13 01:40:49 +00:00
|
|
|
let data = base58::decode_check(inp)?;
|
2016-06-24 19:15:57 +00:00
|
|
|
|
|
|
|
if data.len() != 78 {
|
2024-02-15 05:26:55 +00:00
|
|
|
return Err(InvalidBase58PayloadLengthError { length: data.len() }.into());
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
Xpub::decode(&data)
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 03:41:01 +00:00
|
|
|
impl From<Xpub> for XKeyIdentifier {
|
|
|
|
fn from(key: Xpub) -> XKeyIdentifier { key.identifier() }
|
2022-09-16 12:29:05 +00:00
|
|
|
}
|
|
|
|
|
2023-08-22 03:41:01 +00:00
|
|
|
impl From<&Xpub> for XKeyIdentifier {
|
|
|
|
fn from(key: &Xpub) -> XKeyIdentifier { key.identifier() }
|
2022-09-16 12:29:05 +00:00
|
|
|
}
|
|
|
|
|
2024-02-15 05:26:55 +00:00
|
|
|
/// Decoded base58 data was an invalid length.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct InvalidBase58PayloadLengthError {
|
|
|
|
/// The base58 payload length we got after decoding xpriv/xpub string.
|
|
|
|
pub(crate) length: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvalidBase58PayloadLengthError {
|
|
|
|
/// Returns the invalid payload length.
|
|
|
|
pub fn invalid_base58_payload_length(&self) -> usize { self.length }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for InvalidBase58PayloadLengthError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2024-03-31 01:03:18 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"decoded base58 xpriv/xpub data was an invalid length: {} (expected 78)",
|
|
|
|
self.length
|
|
|
|
)
|
2024-02-15 05:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for InvalidBase58PayloadLengthError {}
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2023-08-10 22:44:58 +00:00
|
|
|
use hex::test_hex_unwrap as hex;
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2022-08-24 06:16:34 +00:00
|
|
|
use super::ChildNumber::{Hardened, Normal};
|
|
|
|
use super::*;
|
2016-06-24 19:15:57 +00:00
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
#[test]
|
|
|
|
fn test_parse_derivation_path() {
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(DerivationPath::from_str("n/0'/0"), Err(Error::InvalidChildNumberFormat));
|
|
|
|
assert_eq!(DerivationPath::from_str("4/m/5"), Err(Error::InvalidChildNumberFormat));
|
|
|
|
assert_eq!(DerivationPath::from_str("//3/0'"), Err(Error::InvalidChildNumberFormat));
|
|
|
|
assert_eq!(DerivationPath::from_str("0h/0x"), Err(Error::InvalidChildNumberFormat));
|
2022-08-24 06:16:34 +00:00
|
|
|
assert_eq!(
|
2024-02-05 16:29:31 +00:00
|
|
|
DerivationPath::from_str("2147483648"),
|
2022-08-24 06:16:34 +00:00
|
|
|
Err(Error::InvalidChildNumber(2147483648))
|
|
|
|
);
|
2019-02-07 21:12:43 +00:00
|
|
|
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(DerivationPath::master(), DerivationPath::from_str("").unwrap());
|
2020-09-26 19:03:28 +00:00
|
|
|
assert_eq!(DerivationPath::master(), DerivationPath::default());
|
2024-04-10 21:20:58 +00:00
|
|
|
|
|
|
|
// Acceptable forms for a master path.
|
|
|
|
assert_eq!(DerivationPath::from_str("m").unwrap(), DerivationPath(vec![]));
|
|
|
|
assert_eq!(DerivationPath::from_str("m/").unwrap(), DerivationPath(vec![]));
|
|
|
|
assert_eq!(DerivationPath::from_str("").unwrap(), DerivationPath(vec![]));
|
|
|
|
|
2019-02-07 21:12:43 +00:00
|
|
|
assert_eq!(
|
2024-02-05 16:29:31 +00:00
|
|
|
DerivationPath::from_str("0'"),
|
2019-02-07 21:12:43 +00:00
|
|
|
Ok(vec![ChildNumber::from_hardened_idx(0).unwrap()].into())
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2024-02-05 16:29:31 +00:00
|
|
|
DerivationPath::from_str("0'/1"),
|
2022-08-24 06:16:34 +00:00
|
|
|
Ok(vec![
|
|
|
|
ChildNumber::from_hardened_idx(0).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(1).unwrap()
|
|
|
|
]
|
|
|
|
.into())
|
2019-02-07 21:12:43 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2024-02-05 16:29:31 +00:00
|
|
|
DerivationPath::from_str("0h/1/2'"),
|
2019-02-07 21:12:43 +00:00
|
|
|
Ok(vec![
|
|
|
|
ChildNumber::from_hardened_idx(0).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(1).unwrap(),
|
|
|
|
ChildNumber::from_hardened_idx(2).unwrap(),
|
2022-08-24 06:16:34 +00:00
|
|
|
]
|
|
|
|
.into())
|
2019-02-07 21:12:43 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2024-02-05 16:29:31 +00:00
|
|
|
DerivationPath::from_str("0'/1/2h/2"),
|
2019-02-07 21:12:43 +00:00
|
|
|
Ok(vec![
|
|
|
|
ChildNumber::from_hardened_idx(0).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(1).unwrap(),
|
|
|
|
ChildNumber::from_hardened_idx(2).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(2).unwrap(),
|
2022-08-24 06:16:34 +00:00
|
|
|
]
|
|
|
|
.into())
|
2019-02-07 21:12:43 +00:00
|
|
|
);
|
2024-04-10 21:20:58 +00:00
|
|
|
let want = DerivationPath::from(vec![
|
|
|
|
ChildNumber::from_hardened_idx(0).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(1).unwrap(),
|
|
|
|
ChildNumber::from_hardened_idx(2).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(2).unwrap(),
|
|
|
|
ChildNumber::from_normal_idx(1000000000).unwrap(),
|
|
|
|
]);
|
|
|
|
assert_eq!(DerivationPath::from_str("0'/1/2'/2/1000000000").unwrap(), want);
|
|
|
|
assert_eq!(DerivationPath::from_str("m/0'/1/2'/2/1000000000").unwrap(), want);
|
|
|
|
|
2024-02-05 16:29:31 +00:00
|
|
|
let s = "0'/50/3'/5/545456";
|
2020-10-14 14:04:18 +00:00
|
|
|
assert_eq!(DerivationPath::from_str(s), s.into_derivation_path());
|
|
|
|
assert_eq!(DerivationPath::from_str(s), s.to_string().into_derivation_path());
|
2024-04-10 21:20:58 +00:00
|
|
|
|
|
|
|
let s = "m/0'/50/3'/5/545456";
|
|
|
|
assert_eq!(DerivationPath::from_str(s), s.into_derivation_path());
|
|
|
|
assert_eq!(DerivationPath::from_str(s), s.to_string().into_derivation_path());
|
2019-02-07 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2019-02-11 22:59:25 +00:00
|
|
|
#[test]
|
2019-08-04 19:27:36 +00:00
|
|
|
fn test_derivation_path_conversion_index() {
|
2024-02-05 16:29:31 +00:00
|
|
|
let path = DerivationPath::from_str("0h/1/2'").unwrap();
|
2019-02-11 22:59:25 +00:00
|
|
|
let numbers: Vec<ChildNumber> = path.clone().into();
|
|
|
|
let path2: DerivationPath = numbers.into();
|
|
|
|
assert_eq!(path, path2);
|
2022-08-24 06:16:34 +00:00
|
|
|
assert_eq!(
|
|
|
|
&path[..2],
|
|
|
|
&[ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()]
|
|
|
|
);
|
2019-02-11 22:59:25 +00:00
|
|
|
let indexed: DerivationPath = path[..2].into();
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(indexed, DerivationPath::from_str("0h/1").unwrap());
|
2019-02-11 22:59:25 +00:00
|
|
|
assert_eq!(indexed.child(ChildNumber::from_hardened_idx(2).unwrap()), path);
|
|
|
|
}
|
|
|
|
|
2022-01-24 01:45:48 +00:00
|
|
|
fn test_path<C: secp256k1::Signing + secp256k1::Verification>(
|
|
|
|
secp: &Secp256k1<C>,
|
2023-11-27 23:40:08 +00:00
|
|
|
network: NetworkKind,
|
2022-01-24 01:45:48 +00:00
|
|
|
seed: &[u8],
|
|
|
|
path: DerivationPath,
|
|
|
|
expected_sk: &str,
|
2022-08-24 06:16:34 +00:00
|
|
|
expected_pk: &str,
|
|
|
|
) {
|
2023-08-21 22:03:55 +00:00
|
|
|
let mut sk = Xpriv::new_master(network, seed).unwrap();
|
|
|
|
let mut pk = Xpub::from_priv(secp, &sk);
|
2018-08-13 00:01:14 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
// Check derivation convenience method for Xpriv
|
2022-01-24 00:31:39 +00:00
|
|
|
assert_eq!(&sk.derive_priv(secp, &path).unwrap().to_string()[..], expected_sk);
|
2018-08-13 00:01:14 +00:00
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
// Check derivation convenience method for Xpub, should error
|
2018-08-13 00:01:14 +00:00
|
|
|
// appropriately if any ChildNumber is hardened
|
2019-02-07 21:13:34 +00:00
|
|
|
if path.0.iter().any(|cnum| cnum.is_hardened()) {
|
2022-01-24 00:31:39 +00:00
|
|
|
assert_eq!(pk.derive_pub(secp, &path), Err(Error::CannotDeriveFromHardenedKey));
|
2018-08-13 00:01:14 +00:00
|
|
|
} else {
|
2022-01-24 00:31:39 +00:00
|
|
|
assert_eq!(&pk.derive_pub(secp, &path).unwrap().to_string()[..], expected_pk);
|
2018-08-13 00:01:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Derive keys, checking hardened and non-hardened derivation one-by-one
|
2019-02-07 21:13:34 +00:00
|
|
|
for &num in path.0.iter() {
|
2016-06-24 19:15:57 +00:00
|
|
|
sk = sk.ckd_priv(secp, num).unwrap();
|
|
|
|
match num {
|
2022-08-24 06:16:34 +00:00
|
|
|
Normal { .. } => {
|
2016-06-24 19:15:57 +00:00
|
|
|
let pk2 = pk.ckd_pub(secp, num).unwrap();
|
2023-08-21 22:03:55 +00:00
|
|
|
pk = Xpub::from_priv(secp, &sk);
|
2016-06-24 19:15:57 +00:00
|
|
|
assert_eq!(pk, pk2);
|
|
|
|
}
|
2022-08-24 06:16:34 +00:00
|
|
|
Hardened { .. } => {
|
|
|
|
assert_eq!(pk.ckd_pub(secp, num), Err(Error::CannotDeriveFromHardenedKey));
|
2023-08-21 22:03:55 +00:00
|
|
|
pk = Xpub::from_priv(secp, &sk);
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check result against expected base58
|
2018-03-09 17:53:20 +00:00
|
|
|
assert_eq!(&sk.to_string()[..], expected_sk);
|
|
|
|
assert_eq!(&pk.to_string()[..], expected_pk);
|
2016-06-24 19:15:57 +00:00
|
|
|
// Check decoded base58 against result
|
2023-08-21 22:03:55 +00:00
|
|
|
let decoded_sk = Xpriv::from_str(expected_sk);
|
|
|
|
let decoded_pk = Xpub::from_str(expected_pk);
|
2016-06-24 19:15:57 +00:00
|
|
|
assert_eq!(Ok(sk), decoded_sk);
|
|
|
|
assert_eq!(Ok(pk), decoded_pk);
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:11:10 +00:00
|
|
|
#[test]
|
|
|
|
fn test_increment() {
|
|
|
|
let idx = 9345497; // randomly generated, I promise
|
|
|
|
let cn = ChildNumber::from_normal_idx(idx).unwrap();
|
2022-08-24 06:16:34 +00:00
|
|
|
assert_eq!(cn.increment().ok(), Some(ChildNumber::from_normal_idx(idx + 1).unwrap()));
|
2019-05-03 15:11:10 +00:00
|
|
|
let cn = ChildNumber::from_hardened_idx(idx).unwrap();
|
2022-08-24 06:16:34 +00:00
|
|
|
assert_eq!(cn.increment().ok(), Some(ChildNumber::from_hardened_idx(idx + 1).unwrap()));
|
2019-05-03 15:11:10 +00:00
|
|
|
|
2022-08-24 06:16:34 +00:00
|
|
|
let max = (1 << 31) - 1;
|
2019-05-03 15:11:10 +00:00
|
|
|
let cn = ChildNumber::from_normal_idx(max).unwrap();
|
2022-08-24 06:16:34 +00:00
|
|
|
assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1 << 31)));
|
2019-05-03 15:11:10 +00:00
|
|
|
let cn = ChildNumber::from_hardened_idx(max).unwrap();
|
2022-08-24 06:16:34 +00:00
|
|
|
assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1 << 31)));
|
2019-05-03 15:11:10 +00:00
|
|
|
|
|
|
|
let cn = ChildNumber::from_normal_idx(350).unwrap();
|
2024-02-05 16:29:31 +00:00
|
|
|
let path = DerivationPath::from_str("42'").unwrap();
|
2019-05-03 15:11:10 +00:00
|
|
|
let mut iter = path.children_from(cn);
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(iter.next(), Some("42'/350".parse().unwrap()));
|
|
|
|
assert_eq!(iter.next(), Some("42'/351".parse().unwrap()));
|
2019-05-03 15:11:10 +00:00
|
|
|
|
2024-02-05 16:29:31 +00:00
|
|
|
let path = DerivationPath::from_str("42'/350'").unwrap();
|
2019-05-03 15:11:10 +00:00
|
|
|
let mut iter = path.normal_children();
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(iter.next(), Some("42'/350'/0".parse().unwrap()));
|
|
|
|
assert_eq!(iter.next(), Some("42'/350'/1".parse().unwrap()));
|
2019-05-03 15:11:10 +00:00
|
|
|
|
2024-02-05 16:29:31 +00:00
|
|
|
let path = DerivationPath::from_str("42'/350'").unwrap();
|
2019-05-03 15:11:10 +00:00
|
|
|
let mut iter = path.hardened_children();
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(iter.next(), Some("42'/350'/0'".parse().unwrap()));
|
|
|
|
assert_eq!(iter.next(), Some("42'/350'/1'".parse().unwrap()));
|
2019-05-03 15:11:10 +00:00
|
|
|
|
|
|
|
let cn = ChildNumber::from_hardened_idx(42350).unwrap();
|
2024-02-05 16:29:31 +00:00
|
|
|
let path = DerivationPath::from_str("42'").unwrap();
|
2019-05-03 15:11:10 +00:00
|
|
|
let mut iter = path.children_from(cn);
|
2024-02-05 16:29:31 +00:00
|
|
|
assert_eq!(iter.next(), Some("42'/42350'".parse().unwrap()));
|
|
|
|
assert_eq!(iter.next(), Some("42'/42351'".parse().unwrap()));
|
2019-05-03 15:11:10 +00:00
|
|
|
|
|
|
|
let cn = ChildNumber::from_hardened_idx(max).unwrap();
|
2024-02-05 16:29:31 +00:00
|
|
|
let path = DerivationPath::from_str("42'").unwrap();
|
2019-05-03 15:11:10 +00:00
|
|
|
let mut iter = path.children_from(cn);
|
|
|
|
assert!(iter.next().is_some());
|
|
|
|
assert!(iter.next().is_none());
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
#[test]
|
|
|
|
fn test_vector_1() {
|
|
|
|
let secp = Secp256k1::new();
|
2022-12-03 19:57:18 +00:00
|
|
|
let seed = hex!("000102030405060708090a0b0c0d0e0f");
|
2018-08-13 00:01:14 +00:00
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
// m
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
|
|
|
|
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8");
|
|
|
|
|
|
|
|
// m/0h
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0h".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
|
|
|
|
"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw");
|
|
|
|
|
|
|
|
// m/0h/1
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
|
|
|
|
"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ");
|
|
|
|
|
|
|
|
// m/0h/1/2h
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
|
|
|
|
"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5");
|
|
|
|
|
|
|
|
// m/0h/1/2h/2
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h/2".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
|
|
|
|
"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV");
|
|
|
|
|
|
|
|
// m/0h/1/2h/2/1000000000
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h/2/1000000000".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
|
|
|
|
"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vector_2() {
|
|
|
|
let secp = Secp256k1::new();
|
2022-12-03 19:57:18 +00:00
|
|
|
let seed = hex!("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");
|
2016-06-24 19:15:57 +00:00
|
|
|
|
|
|
|
// m
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
|
|
|
|
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB");
|
|
|
|
|
|
|
|
// m/0
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
|
|
|
|
"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH");
|
|
|
|
|
|
|
|
// m/0/2147483647h
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
|
|
|
|
"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a");
|
|
|
|
|
|
|
|
// m/0/2147483647h/1
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
|
|
|
|
"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon");
|
|
|
|
|
|
|
|
// m/0/2147483647h/1/2147483646h
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1/2147483646h".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
|
|
|
|
"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL");
|
|
|
|
|
|
|
|
// m/0/2147483647h/1/2147483646h/2
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1/2147483646h/2".parse().unwrap(),
|
2016-06-24 19:15:57 +00:00
|
|
|
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
|
|
|
|
"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt");
|
|
|
|
}
|
|
|
|
|
2018-08-13 00:01:14 +00:00
|
|
|
#[test]
|
|
|
|
fn test_vector_3() {
|
|
|
|
let secp = Secp256k1::new();
|
2022-12-03 19:57:18 +00:00
|
|
|
let seed = hex!("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be");
|
2018-08-13 00:01:14 +00:00
|
|
|
|
|
|
|
// m
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
|
2018-08-13 00:01:14 +00:00
|
|
|
"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
|
|
|
|
"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13");
|
|
|
|
|
|
|
|
// m/0h
|
2024-04-10 21:20:58 +00:00
|
|
|
test_path(&secp, NetworkKind::Main, &seed, "m/0h".parse().unwrap(),
|
2018-08-13 00:01:14 +00:00
|
|
|
"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
|
|
|
|
"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y");
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:15:57 +00:00
|
|
|
#[test]
|
2019-03-26 16:05:51 +00:00
|
|
|
#[cfg(feature = "serde")]
|
2016-06-24 19:15:57 +00:00
|
|
|
pub fn encode_decode_childnumber() {
|
2019-02-14 11:05:20 +00:00
|
|
|
serde_round_trip!(ChildNumber::from_normal_idx(0).unwrap());
|
|
|
|
serde_round_trip!(ChildNumber::from_normal_idx(1).unwrap());
|
|
|
|
serde_round_trip!(ChildNumber::from_normal_idx((1 << 31) - 1).unwrap());
|
|
|
|
serde_round_trip!(ChildNumber::from_hardened_idx(0).unwrap());
|
|
|
|
serde_round_trip!(ChildNumber::from_hardened_idx(1).unwrap());
|
|
|
|
serde_round_trip!(ChildNumber::from_hardened_idx((1 << 31) - 1).unwrap());
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|
2019-07-15 17:41:59 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
pub fn encode_fingerprint_chaincode() {
|
|
|
|
use serde_json;
|
2022-12-23 00:28:17 +00:00
|
|
|
let fp = Fingerprint::from([1u8, 2, 3, 42]);
|
2022-08-24 06:15:33 +00:00
|
|
|
#[rustfmt::skip]
|
2019-07-15 17:41:59 +00:00
|
|
|
let cc = ChainCode::from(
|
2022-12-23 00:28:17 +00:00
|
|
|
[1u8,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]
|
2019-07-15 17:41:59 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
serde_round_trip!(fp);
|
|
|
|
serde_round_trip!(cc);
|
|
|
|
|
|
|
|
assert_eq!("\"0102032a\"", serde_json::to_string(&fp).unwrap());
|
|
|
|
assert_eq!(
|
|
|
|
"\"0102030405060708090001020304050607080900010203040506070809000102\"",
|
|
|
|
serde_json::to_string(&cc).unwrap()
|
|
|
|
);
|
|
|
|
assert_eq!("0102032a", fp.to_string());
|
|
|
|
assert_eq!(
|
|
|
|
"0102030405060708090001020304050607080900010203040506070809000102",
|
|
|
|
cc.to_string()
|
|
|
|
);
|
|
|
|
}
|
2021-02-06 22:41:49 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn fmt_child_number() {
|
2021-06-08 13:19:01 +00:00
|
|
|
assert_eq!("000005h", &format!("{:#06}", ChildNumber::from_hardened_idx(5).unwrap()));
|
|
|
|
assert_eq!("5h", &format!("{:#}", ChildNumber::from_hardened_idx(5).unwrap()));
|
|
|
|
assert_eq!("000005'", &format!("{:06}", ChildNumber::from_hardened_idx(5).unwrap()));
|
|
|
|
assert_eq!("5'", &format!("{}", ChildNumber::from_hardened_idx(5).unwrap()));
|
2021-02-06 22:41:49 +00:00
|
|
|
assert_eq!("42", &format!("{}", ChildNumber::from_normal_idx(42).unwrap()));
|
|
|
|
assert_eq!("000042", &format!("{:06}", ChildNumber::from_normal_idx(42).unwrap()));
|
|
|
|
}
|
2021-12-30 00:53:06 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Secp256k1(InvalidSecretKey)")]
|
|
|
|
fn schnorr_broken_privkey_zeros() {
|
|
|
|
/* this is how we generate key:
|
|
|
|
let mut sk = secp256k1::key::ONE_KEY;
|
|
|
|
|
|
|
|
let zeros = [0u8; 32];
|
|
|
|
unsafe {
|
|
|
|
sk.as_mut_ptr().copy_from(zeros.as_ptr(), 32);
|
|
|
|
}
|
|
|
|
|
2023-08-21 22:03:55 +00:00
|
|
|
let xpriv = Xpriv {
|
2023-11-27 23:40:08 +00:00
|
|
|
network: NetworkKind::Main,
|
2021-12-30 00:53:06 +00:00
|
|
|
depth: 0,
|
|
|
|
parent_fingerprint: Default::default(),
|
|
|
|
child_number: ChildNumber::Normal { index: 0 },
|
|
|
|
private_key: sk,
|
2022-12-23 00:28:17 +00:00
|
|
|
chain_code: ChainCode::from([0u8; 32])
|
2021-12-30 00:53:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
println!("{}", xpriv);
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Xpriv having secret key set to all zeros
|
|
|
|
let xpriv_str = "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx";
|
2023-08-21 22:03:55 +00:00
|
|
|
Xpriv::from_str(xpriv_str).unwrap();
|
2021-12-30 00:53:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Secp256k1(InvalidSecretKey)")]
|
|
|
|
fn schnorr_broken_privkey_ffs() {
|
|
|
|
// Xpriv having secret key set to all 0xFF's
|
|
|
|
let xpriv_str = "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fENZ3QzxW";
|
2023-08-21 22:03:55 +00:00
|
|
|
Xpriv::from_str(xpriv_str).unwrap();
|
2021-12-30 00:53:06 +00:00
|
|
|
}
|
2016-06-24 19:15:57 +00:00
|
|
|
}
|