hd_wallet/
lib.rs

1//! ![License](https://img.shields.io/crates/l/hd-wallet.svg)
2//! [![Docs](https://docs.rs/hd-wallet/badge.svg)](https://docs.rs/hd-wallet)
3//! [![Crates io](https://img.shields.io/crates/v/hd-wallet.svg)](https://crates.io/crates/hd-wallet)
4//! [![Discord](https://img.shields.io/discord/905194001349627914?logo=discord&logoColor=ffffff&label=Discord)](https://discordapp.com/channels/905194001349627914/1285268686147424388)
5//!
6//! # HD wallets derivation
7//!
8//! This crate supports the following HD derivations:
9//! * [SLIP10][slip10-spec] (compatible with [BIP32][bip32-spec]), see [`Slip10`]
10//! * Non-standard [`Edwards`] derivation for ed25519 curve
11//!
12//! To perform HD derivation, use [`HdWallet`] trait.
13//!
14//! ### Example: SLIP10 derivation
15//!
16//! Derive a master key from the seed, and then derive a child key m/1<sub>H</sub>/10:
17//! ```rust
18//! use hd_wallet::{slip10, curves::Secp256k1};
19//!
20//! let seed = b"16-64 bytes of high entropy".as_slice();
21//! let master_key = slip10::derive_master_key::<Secp256k1>(seed)?;
22//! let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
23//!
24//! let child_key_pair = slip10::derive_child_key_pair_with_path(
25//!     &master_key_pair,
26//!     [1 + hd_wallet::H, 10],
27//! );
28//! # Ok::<(), Box<dyn std::error::Error>>(())
29//! ```
30//!
31//! ### Example: via [HdWallet] trait
32//!
33//! [`HdWallet`] trait generalizes HD derivation algorithm, you can use it with generics:
34//! ```rust
35//! use hd_wallet::{Slip10, curves::Secp256r1};
36//!
37//! fn derive_using_generic_algo<E: generic_ec::Curve, Hd: hd_wallet::HdWallet<E>>(
38//!     master_key: hd_wallet::ExtendedKeyPair<E>,
39//! ) -> hd_wallet::ExtendedKeyPair<E>
40//! {
41//!     Hd::derive_child_key_pair_with_path(
42//!         &master_key,
43//!         [1 + hd_wallet::H, 10],
44//!     )
45//! }
46//!
47//! // Use it with any HD derivation:
48//! let seed = b"16-64 bytes of high entropy".as_slice();
49//! let master_key = hd_wallet::slip10::derive_master_key(seed)?;
50//! let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
51//! let child_key = derive_using_generic_algo::<Secp256r1, Slip10>(master_key_pair);
52//!
53//! # Ok::<(), Box<dyn std::error::Error>>(())
54//! ```
55//!
56//! ### Features
57//! * `curve-secp256k1`, `curve-secp256r1`, `curve-ed25519`, `curve-stark` add curve implementation
58//!    into the crate [curves] module
59//! * `all-curves` adds all curves listed above
60//! * `slip10`, `edwards`, `stark` add [`slip10`], [`edwards`], and [`stark`] HD derivations respectively
61//! * `serde` adds `serde::{Serialize, Deserialize}` traits implementation to the types in the library
62//!
63//! ## Join us in Discord!
64//! Feel free to reach out to us [in Discord](https://discordapp.com/channels/905194001349627914/1285268686147424388)!
65//!
66//! [slip10-spec]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md
67//! [bip32-spec]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
68
69#![no_std]
70#![forbid(missing_docs, unsafe_code)]
71#![cfg_attr(not(test), forbid(unused_crate_dependencies))]
72
73use core::ops;
74
75use generic_ec::{Curve, Point, Scalar, SecretScalar};
76
77pub use generic_ec::curves;
78
79#[cfg(feature = "edwards")]
80pub mod edwards;
81pub mod errors;
82#[cfg(feature = "slip10")]
83pub mod slip10;
84#[cfg(feature = "stark")]
85pub mod stark;
86
87#[cfg(feature = "edwards")]
88pub use edwards::Edwards;
89#[cfg(feature = "slip10")]
90pub use slip10::Slip10;
91#[cfg(feature = "stark")]
92pub use stark::Stark;
93
94/// Beginning of hardened child indexes
95///
96/// $H = 2^{31}$ defines the range of hardened indexes. All indexes $i$ such that $H \le i$ are hardened.
97///
98/// ## Example
99/// Derive a child key with a path m/1<sub>H</sub>
100/// ```rust
101/// use hd_wallet::HdWallet;
102///
103/// # let seed = b"do not use this seed in prod :)".as_slice();
104/// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
105/// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
106/// #
107/// let hardened_child = hd_wallet::Slip10::derive_child_key_pair(
108///     &master_key_pair,
109///     1 + hd_wallet::H,
110/// );
111/// #
112/// # Ok::<(), hd_wallet::errors::InvalidLength>(())
113/// ```
114pub const H: u32 = 1 << 31;
115
116/// Child index, whether hardened or not
117#[derive(Clone, Copy, Debug)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "u32"))]
119#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(from = "u32"))]
120pub enum ChildIndex {
121    /// Hardened index
122    Hardened(HardenedIndex),
123    /// Non-hardened index
124    NonHardened(NonHardenedIndex),
125}
126
127/// Child index in range $2^{31} \le i < 2^{32}$ corresponding to a hardened wallet
128#[derive(Clone, Copy, Debug)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "u32"))]
130#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(try_from = "u32"))]
131pub struct HardenedIndex(u32);
132
133/// Child index in range $0 \le i < 2^{31}$ corresponding to a non-hardened wallet
134#[derive(Clone, Copy, Debug)]
135#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "u32"))]
136#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(try_from = "u32"))]
137pub struct NonHardenedIndex(u32);
138
139/// Extended public key
140#[derive(Clone, Copy, Debug)]
141#[cfg_attr(
142    feature = "serde",
143    derive(serde::Serialize, serde::Deserialize),
144    serde(bound = "")
145)]
146pub struct ExtendedPublicKey<E: Curve> {
147    /// The public key that can be used for signature verification
148    pub public_key: Point<E>,
149    /// A chain code that is used to derive child keys
150    pub chain_code: ChainCode,
151}
152
153/// Extended secret key
154#[derive(Clone, Debug)]
155#[cfg_attr(
156    feature = "serde",
157    derive(serde::Serialize, serde::Deserialize),
158    serde(bound = "")
159)]
160pub struct ExtendedSecretKey<E: Curve> {
161    /// The secret key that can be used for signing
162    pub secret_key: SecretScalar<E>,
163    /// A chain code that is used to derive child keys
164    pub chain_code: ChainCode,
165}
166
167/// Pair of extended secret and public keys
168#[derive(Clone, Debug)]
169pub struct ExtendedKeyPair<E: Curve> {
170    public_key: ExtendedPublicKey<E>,
171    secret_key: ExtendedSecretKey<E>,
172}
173
174/// A shift that can be applied to parent key to obtain a child key
175///
176/// It contains an already derived child public key as it needs to be derived
177/// in process of calculating the shift value
178#[derive(Clone, Copy, Debug)]
179#[cfg_attr(
180    feature = "serde",
181    derive(serde::Serialize, serde::Deserialize),
182    serde(bound = "")
183)]
184pub struct DerivedShift<E: Curve> {
185    /// Derived shift
186    pub shift: Scalar<E>,
187    /// Derived child extended public key
188    pub child_public_key: ExtendedPublicKey<E>,
189}
190
191/// Chain code of extended key as defined in SLIP-10
192pub type ChainCode = [u8; 32];
193
194impl HardenedIndex {
195    /// The smallest possible value of hardened index. Equals to $2^{31}$
196    pub const MIN: Self = Self(H);
197    /// The largest possible value of hardened index. Equals to $2^{32} - 1$
198    pub const MAX: Self = Self(u32::MAX);
199}
200impl NonHardenedIndex {
201    /// The smallest possible value of non-hardened index. Equals to $0$
202    pub const MIN: Self = Self(0);
203    /// The largest possible value of non-hardened index. Equals to $2^{31} - 1$
204    pub const MAX: Self = Self(H - 1);
205}
206impl ops::Deref for HardenedIndex {
207    type Target = u32;
208    fn deref(&self) -> &Self::Target {
209        &self.0
210    }
211}
212impl ops::Deref for NonHardenedIndex {
213    type Target = u32;
214    fn deref(&self) -> &Self::Target {
215        &self.0
216    }
217}
218impl ops::Deref for ChildIndex {
219    type Target = u32;
220    fn deref(&self) -> &Self::Target {
221        match self {
222            Self::Hardened(i) => i,
223            Self::NonHardened(i) => i,
224        }
225    }
226}
227impl From<u32> for ChildIndex {
228    fn from(value: u32) -> Self {
229        match value {
230            H.. => Self::Hardened(HardenedIndex(value)),
231            _ => Self::NonHardened(NonHardenedIndex(value)),
232        }
233    }
234}
235impl TryFrom<u32> for HardenedIndex {
236    type Error = errors::OutOfRange;
237    fn try_from(value: u32) -> Result<Self, Self::Error> {
238        match ChildIndex::from(value) {
239            ChildIndex::Hardened(v) => Ok(v),
240            _ => Err(errors::OutOfRange),
241        }
242    }
243}
244impl TryFrom<u32> for NonHardenedIndex {
245    type Error = errors::OutOfRange;
246    fn try_from(value: u32) -> Result<Self, Self::Error> {
247        match ChildIndex::from(value) {
248            ChildIndex::NonHardened(v) => Ok(v),
249            _ => Err(errors::OutOfRange),
250        }
251    }
252}
253impl From<ChildIndex> for u32 {
254    fn from(value: ChildIndex) -> Self {
255        match value {
256            ChildIndex::Hardened(v) => v.0,
257            ChildIndex::NonHardened(v) => v.0,
258        }
259    }
260}
261impl From<HardenedIndex> for u32 {
262    fn from(value: HardenedIndex) -> Self {
263        value.0
264    }
265}
266impl From<NonHardenedIndex> for u32 {
267    fn from(value: NonHardenedIndex) -> Self {
268        value.0
269    }
270}
271impl core::str::FromStr for ChildIndex {
272    type Err = core::num::ParseIntError;
273    fn from_str(s: &str) -> Result<Self, Self::Err> {
274        s.parse::<u32>().map(Into::into)
275    }
276}
277impl core::str::FromStr for HardenedIndex {
278    type Err = errors::ParseChildIndexError;
279    fn from_str(s: &str) -> Result<Self, Self::Err> {
280        let index = s
281            .parse::<u32>()
282            .map_err(errors::ParseChildIndexError::ParseInt)?;
283        HardenedIndex::try_from(index).map_err(errors::ParseChildIndexError::IndexNotInRange)
284    }
285}
286impl core::str::FromStr for NonHardenedIndex {
287    type Err = errors::ParseChildIndexError;
288    fn from_str(s: &str) -> Result<Self, Self::Err> {
289        let index = s
290            .parse::<u32>()
291            .map_err(errors::ParseChildIndexError::ParseInt)?;
292        NonHardenedIndex::try_from(index).map_err(errors::ParseChildIndexError::IndexNotInRange)
293    }
294}
295
296impl<E: Curve> From<&ExtendedSecretKey<E>> for ExtendedPublicKey<E> {
297    fn from(sk: &ExtendedSecretKey<E>) -> Self {
298        ExtendedPublicKey {
299            public_key: Point::generator() * &sk.secret_key,
300            chain_code: sk.chain_code,
301        }
302    }
303}
304
305impl<E: Curve> From<ExtendedSecretKey<E>> for ExtendedKeyPair<E> {
306    fn from(secret_key: ExtendedSecretKey<E>) -> Self {
307        Self {
308            public_key: (&secret_key).into(),
309            secret_key,
310        }
311    }
312}
313
314impl<E: Curve> ExtendedKeyPair<E> {
315    /// Returns chain code of the key
316    pub fn chain_code(&self) -> &ChainCode {
317        debug_assert_eq!(self.public_key.chain_code, self.secret_key.chain_code);
318        &self.public_key.chain_code
319    }
320
321    /// Returns extended public key
322    pub fn public_key(&self) -> &ExtendedPublicKey<E> {
323        &self.public_key
324    }
325
326    /// Returns extended secret key
327    pub fn secret_key(&self) -> &ExtendedSecretKey<E> {
328        &self.secret_key
329    }
330}
331
332#[cfg(feature = "serde")]
333impl<E: Curve> serde::Serialize for ExtendedKeyPair<E> {
334    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
335    where
336        S: serde::Serializer,
337    {
338        self.secret_key.serialize(serializer)
339    }
340}
341
342#[cfg(feature = "serde")]
343impl<'de, E: Curve> serde::Deserialize<'de> for ExtendedKeyPair<E> {
344    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
345    where
346        D: serde::Deserializer<'de>,
347    {
348        let secret_key = ExtendedSecretKey::<E>::deserialize(deserializer)?;
349        Ok(secret_key.into())
350    }
351}
352
353/// * `$t` - type to monomorphise for, like `Slip10` or `Edwards`
354/// * `$m` - current module, module where these functions will appear. Used in doc
355///    tests only
356/// * `$e` - curve supported by this HD derivation, used in doc tests only
357#[cfg(any(feature = "slip10", feature = "edwards", feature = "stark"))]
358macro_rules! create_aliases {
359    ($t:ty, $m:expr) => { $crate::create_aliases!($t, $m, hd_wallet::curves::Secp256k1); };
360    ($t:ty, $m:expr, $e:ty) => {
361        /// Derives a shift for non-hardened child
362        ///
363        #[doc = concat!("Alias to [`<", stringify!($t), " as DeriveShift<E>>::derive_public_shift`](crate::DeriveShift::derive_public_shift)")]
364        pub fn derive_public_shift<E>(
365            parent_public_key: &crate::ExtendedPublicKey<E>,
366            child_index: crate::NonHardenedIndex,
367        ) -> crate::DerivedShift<E>
368        where
369            E: generic_ec::Curve,
370            $t: crate::DeriveShift<E>,
371        {
372            <$t as crate::DeriveShift<E>>::derive_public_shift(parent_public_key, child_index)
373        }
374
375        /// Derive a shift for hardened child
376        ///
377        #[doc = concat!("Alias to [`<", stringify!($t), " as DeriveShift<E>>::derive_hardened_shift`](crate::DeriveShift::derive_hardened_shift)")]
378        pub fn derive_hardened_shift<E>(
379            parent_key: &crate::ExtendedKeyPair<E>,
380            child_index: crate::HardenedIndex,
381        ) -> crate::DerivedShift<E>
382        where
383            E: generic_ec::Curve,
384            $t: crate::DeriveShift<E>,
385        {
386            <$t as crate::DeriveShift<E>>::derive_hardened_shift(parent_key, child_index)
387        }
388
389        /// Derives child extended public key from parent extended public key
390        ///
391        #[doc = concat!("Alias to [`<", stringify!($t), " as HdWallet<E>>::derive_child_public_key`](crate::HdWallet::derive_child_public_key)")]
392        ///
393        /// ### Example
394        /// Derive a master public key m/1
395        /// ```rust,no_run
396        #[doc = concat!( "# type E = ", stringify!($e), ";" )]
397        /// # let seed = b"do not use this seed :)".as_slice();
398        /// # let master_key: hd_wallet::ExtendedSecretKey<E> = todo!();
399        /// # let master_public_key = hd_wallet::ExtendedPublicKey::from(&master_key);
400        /// #
401        #[doc = concat!("let derived_key = hd_wallet::", stringify!($m), "::derive_child_public_key(")]
402        ///     &master_public_key,
403        ///     1.try_into()?,
404        /// );
405        /// # Ok::<(), Box<dyn std::error::Error>>(())
406        /// ```
407        pub fn derive_child_public_key<E>(
408            parent_public_key: &crate::ExtendedPublicKey<E>,
409            child_index: crate::NonHardenedIndex,
410        ) -> crate::ExtendedPublicKey<E>
411        where
412            E: generic_ec::Curve,
413            $t: crate::HdWallet<E>,
414        {
415            <$t as crate::HdWallet<E>>::derive_child_public_key(parent_public_key, child_index)
416        }
417
418        /// Derives child key pair (extended secret key + public key) from parent key pair
419        ///
420        #[doc = concat!("Alias to [`<", stringify!($t), " as HdWallet<E>>::derive_child_key_pair`](crate::HdWallet::derive_child_key_pair)")]
421        ///
422        /// ### Example
423        /// Derive child key m/1<sub>H</sub> from master key
424        /// ```rust,no_run
425        #[doc = concat!( "# type E = ", stringify!($e), ";" )]
426        /// # let seed = b"do not use this seed :)".as_slice();
427        /// # let master_key: hd_wallet::ExtendedSecretKey<E> = todo!();
428        /// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
429        /// #
430        #[doc = concat!("let derived_key = hd_wallet::", stringify!($m), "::derive_child_key_pair(")]
431        ///     &master_key_pair,
432        ///     1 + hd_wallet::H,
433        /// );
434        /// # Ok::<(), Box<dyn std::error::Error>>(())
435        /// ```
436        pub fn derive_child_key_pair<E>(
437            parent_key: &crate::ExtendedKeyPair<E>,
438            child_index: impl Into<crate::ChildIndex>,
439        ) -> crate::ExtendedKeyPair<E>
440        where
441            E: generic_ec::Curve,
442            $t: crate::HdWallet<E>,
443        {
444            <$t as crate::HdWallet<E>>::derive_child_key_pair(parent_key, child_index)
445        }
446
447        /// Derives a child key pair with specified derivation path from parent key pair
448        ///
449        /// Derivation path is a fallible iterator that yields child indexes. If iterator
450        /// yields an error, it's propagated to the caller.
451        ///
452        /// Returns:
453        /// * `Ok(child_key_pair)` if derivation was successful
454        /// * `Err(index_err)` if path contained `Err(index_err)`
455        ///
456        #[doc = concat!("Alias to [`<", stringify!($t), " as HdWallet<E>>::try_derive_child_key_pair_with_path`](crate::HdWallet::try_derive_child_key_pair_with_path)")]
457        ///
458        /// ### Example
459        /// Parse a path from the string and derive a child without extra allocations:
460        /// ```rust,no_run
461        /// use hd_wallet::HdWallet;
462        #[doc = concat!( "# type E = ", stringify!($e), ";" )]
463        /// # let seed = b"16-64 bytes of high entropy".as_slice();
464        /// # let master_key: hd_wallet::ExtendedSecretKey<E> = todo!();
465        /// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
466        ///
467        /// let path = "1/10/2";
468        /// let child_indexes = path.split('/').map(str::parse::<u32>);
469        #[doc = concat!("let child_key = hd_wallet::", stringify!($m), "::try_derive_child_key_pair_with_path(")]
470        ///     &master_key_pair,
471        ///     child_indexes,
472        /// )?;
473        /// # Ok::<_, Box<dyn std::error::Error>>(())
474        /// ```
475        pub fn try_derive_child_key_pair_with_path<E, Err>(
476            parent_key: &crate::ExtendedKeyPair<E>,
477            path: impl IntoIterator<Item = Result<impl Into<crate::ChildIndex>, Err>>,
478        ) -> Result<crate::ExtendedKeyPair<E>, Err>
479        where
480            E: generic_ec::Curve,
481            $t: crate::HdWallet<E>,
482        {
483            <$t as crate::HdWallet<E>>::try_derive_child_key_pair_with_path(parent_key, path)
484        }
485        /// Derives a child key pair with specified derivation path from parent key pair
486        ///
487        /// Derivation path is an iterator that yields child indexes.
488        ///
489        /// If derivation path is empty, `parent_key` is returned
490        ///
491        #[doc = concat!("Alias to [`<", stringify!($t), " as HdWallet<E>>::derive_child_key_pair_with_path`](crate::HdWallet::derive_child_key_pair_with_path)")]
492        ///
493        /// ### Example
494        /// Derive a child key with path m/1/10/1<sub>H</sub>
495        /// ```rust,no_run
496        /// use hd_wallet::HdWallet;
497        #[doc = concat!( "# type E = ", stringify!($e), ";" )]
498        /// # let seed = b"16-64 bytes of high entropy".as_slice();
499        /// # let master_key: hd_wallet::ExtendedSecretKey<E> = todo!();
500        /// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
501        ///
502        #[doc = concat!("let child_key = hd_wallet::", stringify!($m), "::derive_child_key_pair_with_path(")]
503        ///     &master_key_pair,
504        ///     [1, 10, 1 + hd_wallet::H],
505        /// );
506        /// # Ok::<(), Box<dyn std::error::Error>>(())
507        /// ```
508        pub fn derive_child_key_pair_with_path<E>(
509            parent_key: &crate::ExtendedKeyPair<E>,
510            path: impl IntoIterator<Item = impl Into<crate::ChildIndex>>,
511        ) -> crate::ExtendedKeyPair<E>
512        where
513            E: generic_ec::Curve,
514            $t: crate::HdWallet<E>,
515        {
516            <$t as crate::HdWallet<E>>::derive_child_key_pair_with_path(parent_key, path)
517        }
518
519        /// Derives a child public key with specified derivation path
520        ///
521        /// Derivation path is a fallible iterator that yields child indexes. If iterator
522        /// yields an error, it's propagated to the caller.
523        ///
524        /// Returns:
525        /// * `Ok(child_pk)` if derivation was successful
526        /// * `Err(index_err)` if path contained `Err(index_err)`
527        ///
528        #[doc = concat!("Alias to [`<", stringify!($t), " as HdWallet<E>>::try_derive_child_public_key_with_path`](crate::HdWallet::try_derive_child_public_key_with_path)")]
529        ///
530        /// ### Example
531        /// Parse a path from the string and derive a child without extra allocations:
532        /// ```rust,no_run
533        /// use hd_wallet::HdWallet;
534        #[doc = concat!( "# type E = ", stringify!($e), ";" )]
535        /// # let seed = b"16-64 bytes of high entropy".as_slice();
536        /// # let master_key: hd_wallet::ExtendedSecretKey<E> = todo!();
537        /// # let master_public_key = hd_wallet::ExtendedPublicKey::from(&master_key);
538        ///
539        /// let path = "1/10/2";
540        /// let child_indexes = path.split('/').map(str::parse);
541        #[doc = concat!("let child_key = hd_wallet::", stringify!($m), "::try_derive_child_public_key_with_path(")]
542        ///     &master_public_key,
543        ///     child_indexes,
544        /// )?;
545        /// # Ok::<_, Box<dyn std::error::Error>>(())
546        /// ```
547        pub fn try_derive_child_public_key_with_path<E, Err>(
548            parent_public_key: &crate::ExtendedPublicKey<E>,
549            path: impl IntoIterator<Item = Result<crate::NonHardenedIndex, Err>>,
550        ) -> Result<crate::ExtendedPublicKey<E>, Err>
551        where
552            E: generic_ec::Curve,
553            $t: crate::HdWallet<E>,
554        {
555            <$t as crate::HdWallet<E>>::try_derive_child_public_key_with_path(parent_public_key, path)
556        }
557
558        /// Derives a child public key with specified derivation path
559        ///
560        /// Derivation path is an iterator that yields child indexes.
561        ///
562        /// If derivation path is empty, `parent_public_key` is returned
563        ///
564        #[doc = concat!("Alias to [`<", stringify!($t), " as HdWallet<E>>::derive_child_public_key_with_path`](crate::HdWallet::derive_child_public_key_with_path)")]
565        ///
566        /// ### Example
567        /// Derive a child key with path m/1/10
568        /// ```rust,no_run
569        /// use hd_wallet::HdWallet;
570        #[doc = concat!( "# type E = ", stringify!($e), ";" )]
571        /// # let seed = b"16-64 bytes of high entropy".as_slice();
572        /// # let master_key: hd_wallet::ExtendedSecretKey<E> = todo!();
573        /// # let master_public_key = hd_wallet::ExtendedPublicKey::from(&master_key);
574        ///
575        #[doc = concat!("let child_key = hd_wallet::", stringify!($m), "::derive_child_public_key_with_path(")]
576        ///     &master_public_key,
577        ///     [1.try_into()?, 10.try_into()?],
578        /// );
579        /// # Ok::<(), Box<dyn std::error::Error>>(())
580        /// ```
581        pub fn derive_child_public_key_with_path<E>(
582            parent_public_key: &crate::ExtendedPublicKey<E>,
583            path: impl IntoIterator<Item = crate::NonHardenedIndex>,
584        ) -> crate::ExtendedPublicKey<E>
585        where
586            E: generic_ec::Curve,
587            $t: crate::HdWallet<E>,
588        {
589            <$t as crate::HdWallet<E>>::derive_child_public_key_with_path(parent_public_key, path)
590        }
591    };
592}
593#[cfg(any(feature = "slip10", feature = "edwards", feature = "stark"))]
594pub(crate) use create_aliases;
595
596/// HD derivation
597pub trait HdWallet<E: Curve>: DeriveShift<E> {
598    /// Derives child extended public key from parent extended public key
599    ///
600    /// ### Example
601    /// Derive a master public key m/1
602    /// ```rust
603    /// use hd_wallet::HdWallet;
604    ///
605    /// # let seed = b"do not use this seed :)".as_slice();
606    /// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
607    /// # let master_public_key = hd_wallet::ExtendedPublicKey::from(&master_key);
608    /// #
609    /// let derived_key = hd_wallet::Slip10::derive_child_public_key(
610    ///     &master_public_key,
611    ///     1.try_into()?,
612    /// );
613    /// # Ok::<(), Box<dyn std::error::Error>>(())
614    /// ```
615    fn derive_child_public_key(
616        parent_public_key: &ExtendedPublicKey<E>,
617        child_index: NonHardenedIndex,
618    ) -> ExtendedPublicKey<E> {
619        Self::derive_public_shift(parent_public_key, child_index).child_public_key
620    }
621
622    /// Derives child key pair (extended secret key + public key) from parent key pair
623    ///
624    /// ### Example
625    /// Derive child key m/1<sub>H</sub> from master key
626    /// ```rust
627    /// use hd_wallet::HdWallet;
628    ///
629    /// # let seed = b"do not use this seed :)".as_slice();
630    /// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
631    /// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
632    /// #
633    /// let derived_key = hd_wallet::Slip10::derive_child_key_pair(
634    ///     &master_key_pair,
635    ///     1 + hd_wallet::H,
636    /// );
637    /// # Ok::<(), Box<dyn std::error::Error>>(())
638    /// ```
639    fn derive_child_key_pair(
640        parent_key: &ExtendedKeyPair<E>,
641        child_index: impl Into<ChildIndex>,
642    ) -> ExtendedKeyPair<E> {
643        let child_index = child_index.into();
644        let shift = match child_index {
645            ChildIndex::Hardened(i) => Self::derive_hardened_shift(parent_key, i),
646            ChildIndex::NonHardened(i) => Self::derive_public_shift(&parent_key.public_key, i),
647        };
648        let mut child_sk = &parent_key.secret_key.secret_key + shift.shift;
649        let child_sk = SecretScalar::new(&mut child_sk);
650        ExtendedKeyPair {
651            secret_key: ExtendedSecretKey {
652                secret_key: child_sk,
653                chain_code: shift.child_public_key.chain_code,
654            },
655            public_key: shift.child_public_key,
656        }
657    }
658
659    /// Derives a child key pair with specified derivation path from parent key pair
660    ///
661    /// Derivation path is a fallible iterator that yields child indexes. If iterator
662    /// yields an error, it's propagated to the caller.
663    ///
664    /// Returns:
665    /// * `Ok(child_key_pair)` if derivation was successful
666    /// * `Err(index_err)` if path contained `Err(index_err)`
667    ///
668    /// ### Example
669    /// Parse a path from the string and derive a child without extra allocations:
670    /// ```rust
671    /// use hd_wallet::HdWallet;
672    /// # let seed = b"16-64 bytes of high entropy".as_slice();
673    /// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
674    /// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
675    ///
676    /// let path = "1/10/2";
677    /// let child_indexes = path.split('/').map(str::parse::<u32>);
678    /// let child_key = hd_wallet::Slip10::try_derive_child_key_pair_with_path(
679    ///     &master_key_pair,
680    ///     child_indexes,
681    /// )?;
682    /// # Ok::<_, Box<dyn std::error::Error>>(())
683    /// ```
684    fn try_derive_child_key_pair_with_path<Err>(
685        parent_key: &ExtendedKeyPair<E>,
686        path: impl IntoIterator<Item = Result<impl Into<ChildIndex>, Err>>,
687    ) -> Result<ExtendedKeyPair<E>, Err> {
688        let mut derived_key = parent_key.clone();
689        for child_index in path {
690            derived_key = Self::derive_child_key_pair(&derived_key, child_index?);
691        }
692        Ok(derived_key)
693    }
694
695    /// Derives a child key pair with specified derivation path from parent key pair
696    ///
697    /// Derivation path is an iterator that yields child indexes.
698    ///
699    /// If derivation path is empty, `parent_key` is returned
700    ///
701    /// ### Example
702    /// Derive a child key with path m/1/10/1<sub>H</sub>
703    /// ```rust
704    /// use hd_wallet::HdWallet;
705    /// # let seed = b"16-64 bytes of high entropy".as_slice();
706    /// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
707    /// # let master_key_pair = hd_wallet::ExtendedKeyPair::from(master_key);
708    ///
709    /// let child_key = hd_wallet::Slip10::derive_child_key_pair_with_path(
710    ///     &master_key_pair,
711    ///     [1, 10, 1 + hd_wallet::H],
712    /// );
713    /// # Ok::<(), Box<dyn std::error::Error>>(())
714    /// ```
715    fn derive_child_key_pair_with_path(
716        parent_key: &ExtendedKeyPair<E>,
717        path: impl IntoIterator<Item = impl Into<ChildIndex>>,
718    ) -> ExtendedKeyPair<E> {
719        let result = Self::try_derive_child_key_pair_with_path(
720            parent_key,
721            path.into_iter().map(Ok::<_, core::convert::Infallible>),
722        );
723        match result {
724            Ok(key) => key,
725            Err(err) => match err {},
726        }
727    }
728
729    /// Derives a child public key with specified derivation path
730    ///
731    /// Derivation path is a fallible iterator that yields child indexes. If iterator
732    /// yields an error, it's propagated to the caller.
733    ///
734    /// Returns:
735    /// * `Ok(child_pk)` if derivation was successful
736    /// * `Err(index_err)` if path contained `Err(index_err)`
737    ///
738    /// ### Example
739    /// Parse a path from the string and derive a child without extra allocations:
740    /// ```rust
741    /// use hd_wallet::HdWallet;
742    /// # let seed = b"16-64 bytes of high entropy".as_slice();
743    /// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
744    /// # let master_public_key = hd_wallet::ExtendedPublicKey::from(&master_key);
745    ///
746    /// let path = "1/10/2";
747    /// let child_indexes = path.split('/').map(str::parse);
748    /// let child_key = hd_wallet::Slip10::try_derive_child_public_key_with_path(
749    ///     &master_public_key,
750    ///     child_indexes,
751    /// )?;
752    /// # Ok::<_, Box<dyn std::error::Error>>(())
753    /// ```
754    fn try_derive_child_public_key_with_path<Err>(
755        parent_public_key: &ExtendedPublicKey<E>,
756        path: impl IntoIterator<Item = Result<NonHardenedIndex, Err>>,
757    ) -> Result<ExtendedPublicKey<E>, Err> {
758        let mut derived_key = *parent_public_key;
759        for child_index in path {
760            derived_key = Self::derive_child_public_key(&derived_key, child_index?);
761        }
762        Ok(derived_key)
763    }
764
765    /// Derives a child public key with specified derivation path
766    ///
767    /// Derivation path is an iterator that yields child indexes.
768    ///
769    /// If derivation path is empty, `parent_public_key` is returned
770    ///
771    /// ### Example
772    /// Derive a child key with path m/1/10
773    /// ```rust
774    /// use hd_wallet::HdWallet;
775    /// # let seed = b"16-64 bytes of high entropy".as_slice();
776    /// # let master_key = hd_wallet::slip10::derive_master_key::<hd_wallet::curves::Secp256k1>(seed)?;
777    /// # let master_public_key = hd_wallet::ExtendedPublicKey::from(&master_key);
778    ///
779    /// let child_key = hd_wallet::Slip10::derive_child_public_key_with_path(
780    ///     &master_public_key,
781    ///     [1.try_into()?, 10.try_into()?],
782    /// );
783    /// # Ok::<(), Box<dyn std::error::Error>>(())
784    /// ```
785    fn derive_child_public_key_with_path(
786        parent_public_key: &ExtendedPublicKey<E>,
787        path: impl IntoIterator<Item = NonHardenedIndex>,
788    ) -> ExtendedPublicKey<E> {
789        let result = Self::try_derive_child_public_key_with_path(
790            parent_public_key,
791            path.into_iter().map(Ok::<_, core::convert::Infallible>),
792        );
793        match result {
794            Ok(key) => key,
795            Err(err) => match err {},
796        }
797    }
798}
799
800impl<E: Curve, S: DeriveShift<E>> HdWallet<E> for S {}
801
802/// Core functionality of HD wallet derivation, everything is defined on top of it
803pub trait DeriveShift<E: Curve> {
804    /// Derives a shift for non-hardened child
805    ///
806    /// We support only HD derivations that are always defined. This function may not panic.
807    fn derive_public_shift(
808        parent_public_key: &ExtendedPublicKey<E>,
809        child_index: NonHardenedIndex,
810    ) -> DerivedShift<E>;
811
812    /// Derive a shift for hardened child
813    ///
814    /// We support only HD derivations that are always defined. This function may not panic.
815    fn derive_hardened_shift(
816        parent_key: &ExtendedKeyPair<E>,
817        child_index: HardenedIndex,
818    ) -> DerivedShift<E>;
819}