Skip to content

Commit

Permalink
solution: conversion to bitcoin-lib types
Browse files Browse the repository at this point in the history
  • Loading branch information
splix committed Jul 15, 2020
1 parent 1c6f2c9 commit 5f5dfc4
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 4 deletions.
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ path = "src/lib.rs"

[dependencies]
byteorder= "1.3.4"
bitcoin = { version = "0.21.0", optional = true }

[dev-dependencies]
rand = "0.7.3"
quickcheck = "0.9.2"
quickcheck = "0.9.2"

[features]
default = []
with-bitcoin = ["bitcoin"]
36 changes: 34 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
= HD Path for Rust
:lib-version: 0.2.0-alpha

Rust crate that implements common structures and utilities to operate HD Path defined by Bitcoin's BIP-32 standard.

Expand All @@ -22,9 +23,10 @@ All supported standards:
== Use

.Cargo.toml:
[source,toml,subs="attributes"]
----
[dependencies]
hdpath = "0.1"
hdpath = "{lib-version}"
----

=== Examples
Expand Down Expand Up @@ -82,9 +84,39 @@ fn user_path(index: u32) -> Result<StandardHDPath, ()> {
}
----

=== Use with bitcoin library

Enable `with-bitcoin` feature, that provides extra methods for compatibility with bitcoin lib.
It includes conversion into `Vec<ChildNumber>` and `DerivationPath`.

[source,toml,subs="attributes"]
----
hdpath = { version = "{lib-version}", features = ["with-bitcoin"] }
----

.Convert to DerivationPath
[source,rust]
----
use hdpath::{StandardHDPath};
use secp256k1::Secp256k1;
use bitcoin::{
network::constants::Network,
util::bip32::{ExtendedPrivKey, DerivationPath}
};
fn get_pk(seed: &[u8], hd_path: &StandardHDPath) -> ExtendedPrivKey {
let secp = Secp256k1::new();
ExtendedPrivKey::new_master(Network::Bitcoin, seed)
// we convert HD Path to bitcoin lib format (DerivationPath)
.and_then(|k| k.derive_priv(&secp, &DerivationPath::from(hd_path)))
.unwrap()
}
----

== License

Copyright 2020 ETCDEV GmbH
Copyright 2020 EmeraldPay, Inc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
30 changes: 29 additions & 1 deletion crates.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,32 @@ fn user_path(index: u32) -> Result<StandardHDPath, ()> {
Err(())
}
}
```
```

## How to use with bitcoin library

Enable `with-bitcoin` feature, that provides extra methods for compatibility with bitcoin lib.
It includes conversion into `Vec<ChildNumber>` and `DerivationPath`.

```toml
hdpath = { version = "0.2.0", features = ["with-bitcoin"] }
```

Convert to DerivationPath when needed

```rust
use hdpath::{StandardHDPath};
use secp256k1::Secp256k1;
use bitcoin::{
network::constants::Network,
util::bip32::{ExtendedPrivKey, DerivationPath}
};

fn get_pk(seed: &[u8], hd_path: &StandardHDPath) -> ExtendedPrivKey {
let secp = Secp256k1::new();
ExtendedPrivKey::new_master(Network::Bitcoin, seed)
// we convert HD Path to bitcoin lib format (DerivationPath)
.and_then(|k| k.derive_priv(&secp, &DerivationPath::from(hd_path)))
.unwrap()
}
```
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
//! ```
//!
extern crate byteorder;
#[cfg(feature = "with-bitcoin")]
extern crate bitcoin;

mod errors;
mod path_custom;
Expand Down
60 changes: 60 additions & 0 deletions src/path_standard.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{Purpose, PathValue, Error, CustomHDPath};
use std::convert::{TryFrom, TryInto};
use byteorder::{WriteBytesExt, BigEndian};
#[cfg(feature = "with-bitcoin")]
use bitcoin::util::bip32::{ChildNumber, DerivationPath};

/// Standard HD Path for [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki),
/// [BIP-49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki), [BIP-84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki)
Expand Down Expand Up @@ -217,6 +219,46 @@ impl ToString for StandardHDPath {
}
}

#[cfg(feature = "with-bitcoin")]
impl std::convert::From<&StandardHDPath> for Vec<ChildNumber> {
fn from(value: &StandardHDPath) -> Self {
let result = [
ChildNumber::from_hardened_idx(value.purpose().as_value().as_number())
.expect("Purpose is not Hardened"),
ChildNumber::from_hardened_idx(value.coin_type())
.expect("Coin Type is not Hardened"),
ChildNumber::from_hardened_idx(value.account())
.expect("Account is not Hardened"),
ChildNumber::from_normal_idx(value.change())
.expect("Change is Hardened"),
ChildNumber::from_normal_idx(value.index())
.expect("Index is Hardened"),
];
return result.to_vec();
}
}

#[cfg(feature = "with-bitcoin")]
impl std::convert::From<StandardHDPath> for Vec<ChildNumber> {
fn from(value: StandardHDPath) -> Self {
Vec::<ChildNumber>::from(&value)
}
}

#[cfg(feature = "with-bitcoin")]
impl std::convert::From<StandardHDPath> for DerivationPath {
fn from(value: StandardHDPath) -> Self {
DerivationPath::from(Vec::<ChildNumber>::from(&value))
}
}

#[cfg(feature = "with-bitcoin")]
impl std::convert::From<&StandardHDPath> for DerivationPath {
fn from(value: &StandardHDPath) -> Self {
DerivationPath::from(Vec::<ChildNumber>::from(value))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -602,6 +644,24 @@ mod tests {
}
}
}
}

#[cfg(all(test, feature = "with-bitcoin"))]
mod tests_with_bitcoin {
use super::*;
use std::convert::TryFrom;
use bitcoin::util::bip32::ChildNumber;

#[test]
pub fn convert_to_childnumbers() {
let hdpath = StandardHDPath::try_from("m/44'/60'/2'/0/3581").unwrap();
let childs: Vec<ChildNumber> = hdpath.into();
assert_eq!(childs.len(), 5);
assert_eq!(childs[0], ChildNumber::from_hardened_idx(44).unwrap());
assert_eq!(childs[1], ChildNumber::from_hardened_idx(60).unwrap());
assert_eq!(childs[2], ChildNumber::from_hardened_idx(2).unwrap());
assert_eq!(childs[3], ChildNumber::from_normal_idx(0).unwrap());
assert_eq!(childs[4], ChildNumber::from_normal_idx(3581).unwrap());
}

}

0 comments on commit 5f5dfc4

Please sign in to comment.