bip32: Add additional methods and traits to DerivationPath

- From<&[ChildNumber]> (cloning)
- AsRef<[ChildNumber]>
- std::iter::FromIterator<ChildNumber>
- std::iter::IntoIterator<ChildNumber>
- std::ops::Index (returning &[ChildNumber])

Also add two methods:
- child(&self, ChildNumber) -> DerivationPath
- into_child(self, ChildNumber) -> DerivationPath
This commit is contained in:
Steven Roose 2019-02-11 22:59:25 +00:00
parent 1373969805
commit dce81b623e
No known key found for this signature in database
GPG Key ID: 7FC91380BB4CE800
1 changed files with 66 additions and 7 deletions

View File

@ -204,7 +204,8 @@ impl serde::Serialize for ChildNumber {
/// A BIP-32 derivation path.
#[derive(Clone, PartialEq, Eq)]
pub struct DerivationPath(pub Vec<ChildNumber>);
pub struct DerivationPath(Vec<ChildNumber>);
impl_index_newtype!(DerivationPath, ChildNumber);
impl From<Vec<ChildNumber>> for DerivationPath {
fn from(numbers: Vec<ChildNumber>) -> Self {
@ -218,6 +219,32 @@ impl Into<Vec<ChildNumber>> for DerivationPath {
}
}
impl<'a> From<&'a [ChildNumber]> for DerivationPath {
fn from(numbers: &'a [ChildNumber]) -> Self {
DerivationPath(numbers.to_vec())
}
}
impl ::std::iter::FromIterator<ChildNumber> for DerivationPath {
fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = ChildNumber> {
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<C: secp256k1::Signing>(
///
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
pub fn derive_priv<C: secp256k1::Signing, P: AsRef<[ChildNumber]>>(
&self,
secp: &Secp256k1<C>,
path: &DerivationPath,
path: &P,
) -> Result<ExtendedPrivKey, Error> {
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<C: secp256k1::Verification>(
///
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
pub fn derive_pub<C: secp256k1::Verification, P: AsRef<[ChildNumber]>>(
&self,
secp: &Secp256k1<C>,
path: &DerivationPath,
path: &P,
) -> Result<ExtendedPubKey, Error> {
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<ChildNumber> = 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<C: secp256k1::Signing + secp256k1::Verification>(secp: &Secp256k1<C>,
network: Network,
seed: &[u8],