Merge pull request #498 from LNP-BP/pending/derivation

Derivation path improvements, closes #473
This commit is contained in:
Andrew Poelstra 2020-12-28 00:53:25 +00:00 committed by GitHub
commit 1cc466fec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 47 additions and 0 deletions

View File

@ -210,12 +210,43 @@ impl serde::Serialize for ChildNumber {
} }
} }
/// Trait that allows possibly failable conversion from a type into a
/// derivation path
pub trait IntoDerivationPath {
/// Convers a given type into a [`DerivationPath`] with possible error
fn into_derivation_path(self) -> Result<DerivationPath, Error>;
}
/// A BIP-32 derivation path. /// A BIP-32 derivation path.
#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct DerivationPath(Vec<ChildNumber>); pub struct DerivationPath(Vec<ChildNumber>);
impl_index_newtype!(DerivationPath, ChildNumber); impl_index_newtype!(DerivationPath, ChildNumber);
serde_string_impl!(DerivationPath, "a BIP-32 derivation path"); serde_string_impl!(DerivationPath, "a BIP-32 derivation path");
impl Default for DerivationPath {
fn default() -> DerivationPath {
DerivationPath::master()
}
}
impl<T> IntoDerivationPath for T where T: Into<DerivationPath> {
fn into_derivation_path(self) -> Result<DerivationPath, Error> {
Ok(self.into())
}
}
impl IntoDerivationPath for String {
fn into_derivation_path(self) -> Result<DerivationPath, Error> {
self.parse()
}
}
impl<'a> IntoDerivationPath for &'a str {
fn into_derivation_path(self) -> Result<DerivationPath, Error> {
self.parse()
}
}
impl From<Vec<ChildNumber>> for DerivationPath { impl From<Vec<ChildNumber>> for DerivationPath {
fn from(numbers: Vec<ChildNumber>) -> Self { fn from(numbers: Vec<ChildNumber>) -> Self {
DerivationPath(numbers) DerivationPath(numbers)
@ -304,6 +335,17 @@ impl DerivationPath {
self.0.len() self.0.len()
} }
/// Returns derivation path for a master key (i.e. empty derivation path)
pub fn master() -> DerivationPath {
DerivationPath(vec![])
}
/// Returns whether derivation path represents master key (i.e. it's length
/// is empty). True for `m` path.
pub fn is_master(&self) -> bool {
self.0.is_empty()
}
/// Create a new [DerivationPath] that is a child of this one. /// Create a new [DerivationPath] that is a child of this one.
pub fn child(&self, cn: ChildNumber) -> DerivationPath { pub fn child(&self, cn: ChildNumber) -> DerivationPath {
let mut path = self.0.clone(); let mut path = self.0.clone();
@ -763,6 +805,8 @@ mod tests {
assert_eq!(DerivationPath::from_str("m/0h/0x"), Err(Error::InvalidChildNumberFormat)); assert_eq!(DerivationPath::from_str("m/0h/0x"), Err(Error::InvalidChildNumberFormat));
assert_eq!(DerivationPath::from_str("m/2147483648"), Err(Error::InvalidChildNumber(2147483648))); assert_eq!(DerivationPath::from_str("m/2147483648"), Err(Error::InvalidChildNumber(2147483648)));
assert_eq!(DerivationPath::master(), DerivationPath::from_str("m").unwrap());
assert_eq!(DerivationPath::master(), DerivationPath::default());
assert_eq!(DerivationPath::from_str("m"), Ok(vec![].into())); assert_eq!(DerivationPath::from_str("m"), Ok(vec![].into()));
assert_eq!( assert_eq!(
DerivationPath::from_str("m/0'"), DerivationPath::from_str("m/0'"),
@ -799,6 +843,9 @@ mod tests {
ChildNumber::from_normal_idx(1000000000).unwrap(), ChildNumber::from_normal_idx(1000000000).unwrap(),
].into()) ].into())
); );
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());
} }
#[test] #[test]