diff --git a/Cargo.lock b/Cargo.lock
index c290deb..70ab4d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -23,6 +23,12 @@ dependencies = [
"generic-array",
]
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -275,6 +281,17 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
[[package]]
name = "group"
version = "0.13.0"
@@ -295,6 +312,7 @@ dependencies = [
"hex",
"hex-literal",
"hmac",
+ "rand",
"serde",
"sha2",
"subtle",
@@ -390,6 +408,15 @@ dependencies = [
"educe",
]
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
[[package]]
name = "primeorder"
version = "0.13.6"
@@ -417,11 +444,35 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
[[package]]
name = "rustc_version"
@@ -556,6 +607,33 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
[[package]]
name = "zeroize"
version = "1.8.1"
diff --git a/Cargo.toml b/Cargo.toml
index ee528d6..b0f16db 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,7 @@ serde = { version = "1", default-features = false, features = ["derive"], option
[dev-dependencies]
hex = "0.4"
hex-literal = "0.4"
+rand = "0.8"
[features]
std = []
diff --git a/src/lib.rs b/src/lib.rs
index 1ee2d22..1426c38 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,12 +1,12 @@
//! # HD wallets derivation
//!
-//! This crate supports the following ways of HD derivation:
-//! * [SLIP10][slip10-spec] (compatible with [BIP32][bip32-spec]), see [slip10] module
+//! This crate supports the following HD derivations:
+//! * [SLIP10][slip10-spec] (compatible with [BIP32][bip32-spec]), see [`Slip10`]
//! * Non-standard [`Edwards`] derivation for ed25519 curve
//!
//! To perform HD derivation, use [`HdWallet`] trait.
//!
-//! ### Examples: SLIP10 derivation
+//! ### Example: SLIP10 derivation
//!
//! Derive a master key from the seed, and then derive a child key m/1H/10:
//! ```rust
@@ -316,7 +316,7 @@ impl<'de, E: Curve> serde::Deserialize<'de> for ExtendedKeyPair {
}
}
-/// Type of HD wallet, like [`Slip10`]
+/// HD derivation
pub trait HdWallet: DeriveShift {
/// Derives child extended public key from parent extended public key
///
@@ -571,7 +571,7 @@ pub trait DeriveShift {
/// `Slip10Like` will not follow SLIP10 standard
/// 2. it's quite inefficient
///
-/// Prefer using [`Edwards`](Edwards) derivation method for ed25519 curve.
+/// Prefer using [`Edwards`] derivation method for ed25519 curve.
pub struct Slip10Like;
impl DeriveShift for Slip10Like {
@@ -643,7 +643,42 @@ impl Slip10Like {
/// [SLIP10][slip10-spec] HD wallet derivation
///
-/// Performs HD derivation as defined in the spec. Refer to [`slip10`] module for more details.
+/// Performs HD derivation as defined in the spec. Only supports secp256k1 and secp256r1 curves.
+///
+/// ## Limitations
+/// We do not support SLIP10 instantiated with ed25519 or curve25519 due to the limitations.
+/// Ed25519 and curve25519 are special-cases in SLIP10 standard, they only support hardened
+/// derivation, and they operate on EdDSA and X25519 private keys instead of elliptic points
+/// and scalars as in other cases. This library only supports HD derivations in which
+/// secret keys are represented as scalars and public keys as points, see [`ExtendedSecretKey`]
+/// and [`ExtendedPublicKey`].
+///
+/// If you need HD derivation on Ed25519 curve, we recommend using [`Edwards`] HD derivation,
+/// which supports both hardened and non-hardened derivation.
+///
+/// ## Master key derivation from the seed
+/// [`slip10::derive_master_key`] can be used to derive a master key from the seed as defined
+/// in the spec.
+///
+/// ## Example
+/// Derive a master key from the seed, and then derive a child key m/1H/10:
+/// ```rust
+/// use hd_wallet::{HdWallet, Slip10, curves::Secp256k1};
+///
+/// let seed = b"16-64 bytes of high entropy".as_slice();
+/// let master_key = hd_wallet::slip10::derive_master_key::(seed)?;
+/// let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
+///
+/// let child_key_pair = Slip10::derive_child_key_pair_with_path(
+/// &master_key_pair,
+/// [1 + hd_wallet::H, 10],
+/// );
+/// # Ok::<(), Box>(())
+/// ```
+///
+/// ## SLIP10-like derivation
+/// SLIP10 is only defined for a few curves, but it can be extended to support any curve.
+/// See [`Slip10Like`] if you need other curves than is supported by SLIP10.
///
/// [slip10-spec]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md
pub struct Slip10;
@@ -691,6 +726,26 @@ fn split_into_two_halves(
/// This type of derivation isn't defined in any known to us standards, but it can be often
/// found in other libraries. It is secure and efficient (much more efficient than using
/// [`Slip10Like`](Slip10Like), for instance).
+///
+/// ## Example
+/// ```rust
+/// use hd_wallet::{HdWallet, Edwards, curves::Ed25519};
+///
+/// # fn load_key() -> hd_wallet::ExtendedKeyPair {
+/// # hd_wallet::ExtendedSecretKey {
+/// # secret_key: generic_ec::SecretScalar::random(&mut rand::rngs::OsRng),
+/// # chain_code: rand::Rng::gen(&mut rand::rngs::OsRng),
+/// # }.into()
+/// # }
+/// #
+/// let parent_key: hd_wallet::ExtendedKeyPair = load_key();
+///
+/// let child_key_pair = Edwards::derive_child_key_pair_with_path(
+/// &parent_key,
+/// [1 + hd_wallet::H, 10],
+/// );
+/// # Ok::<(), Box>(())
+/// ```
pub struct Edwards;
#[cfg(feature = "curve-ed25519")]
diff --git a/src/slip10.rs b/src/slip10.rs
index c400435..18ed66e 100644
--- a/src/slip10.rs
+++ b/src/slip10.rs
@@ -1,9 +1,9 @@
-//! SLIP10-specific function
+//! SLIP10 derivation
//!
//! [SLIP10][slip10-spec] is a specification for implementing HD wallets. It aims at supporting many
//! curves while being compatible with [BIP32][bip32-spec].
//!
-//! We provide two [`HdWallet`] implementations:
+//! We provide two [`HdWallet`](crate::HdWallet) implementations:
//! * [`Slip10`] which follows the spec and only supports the curves defined in the standard (except
//! for curves that are explicitly unsupported by this library)
//! * [`Slip10Like`] which generalizes slip10, it is defined for any curve that meets requirements
@@ -13,7 +13,7 @@
use hmac::Mac as _;
-pub use crate::Slip10Like;
+pub use crate::{Slip10, Slip10Like};
/// Marker for a curve supported by SLIP10 specs and this library
///