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 ///