diff --git a/src/util/bip32.rs b/src/util/bip32.rs index aac4223..a2ab6de 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -204,7 +204,8 @@ impl serde::Serialize for ChildNumber { /// A BIP-32 derivation path. #[derive(Clone, PartialEq, Eq)] -pub struct DerivationPath(pub Vec); +pub struct DerivationPath(Vec); +impl_index_newtype!(DerivationPath, ChildNumber); impl From> for DerivationPath { fn from(numbers: Vec) -> Self { @@ -218,6 +219,32 @@ impl Into> for DerivationPath { } } +impl<'a> From<&'a [ChildNumber]> for DerivationPath { + fn from(numbers: &'a [ChildNumber]) -> Self { + DerivationPath(numbers.to_vec()) + } +} + +impl ::std::iter::FromIterator for DerivationPath { + fn from_iter(iter: T) -> Self where T: IntoIterator { + DerivationPath(Vec::from_iter(iter)) + } +} + +impl<'a> ::std::iter::IntoIterator for &'a DerivationPath { + type Item = &'a ChildNumber; + type IntoIter = ::std::slice::Iter<'a, ChildNumber>; + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl AsRef<[ChildNumber]> for DerivationPath { + fn as_ref(&self) -> &[ChildNumber] { + &self.0 + } +} + impl FromStr for DerivationPath { type Err = Error; @@ -233,6 +260,22 @@ impl FromStr for DerivationPath { } } +impl DerivationPath { + /// Create a new DerivationPath that is a child of this one. + pub fn child(&self, cn: ChildNumber) -> DerivationPath { + let mut path = self.0.clone(); + path.push(cn); + DerivationPath(path) + } + + /// Convert into a DerivationPath that is a child of this one. + pub fn into_child(self, cn: ChildNumber) -> DerivationPath { + let mut path = self.0; + path.push(cn); + DerivationPath(path) + } +} + impl fmt::Display for DerivationPath { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("m")?; @@ -361,13 +404,15 @@ impl ExtendedPrivKey { } /// Attempts to derive an extended private key from a path. - pub fn derive_priv( + /// + /// The `path` argument can be both of type `DerivationPath` or `Vec`. + pub fn derive_priv>( &self, secp: &Secp256k1, - path: &DerivationPath, + path: &P, ) -> Result { let mut sk: ExtendedPrivKey = *self; - for cnum in &path.0 { + for cnum in path.as_ref() { sk = sk.ckd_priv(secp, *cnum)?; } Ok(sk) @@ -430,13 +475,15 @@ impl ExtendedPubKey { } /// Attempts to derive an extended public key from a path. - pub fn derive_pub( + /// + /// The `path` argument can be both of type `DerivationPath` or `Vec`. + pub fn derive_pub>( &self, secp: &Secp256k1, - path: &DerivationPath, + path: &P, ) -> Result { let mut pk: ExtendedPubKey = *self; - for cnum in &path.0 { + for cnum in path.as_ref() { pk = pk.ckd_pub(secp, *cnum)? } Ok(pk) @@ -657,6 +704,18 @@ mod tests { ); } + #[test] + fn test_derivation_path_convertion_index() { + let path = DerivationPath::from_str("m/0h/1/2'").unwrap(); + let numbers: Vec = path.clone().into(); + let path2: DerivationPath = numbers.into(); + assert_eq!(path, path2); + assert_eq!(&path[..2], &[ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()]); + let indexed: DerivationPath = path[..2].into(); + assert_eq!(indexed, DerivationPath::from_str("m/0h/1").unwrap()); + assert_eq!(indexed.child(ChildNumber::from_hardened_idx(2).unwrap()), path); + } + fn test_path(secp: &Secp256k1, network: Network, seed: &[u8],