slip_10/
lib.rs

1//! SLIP-10: Deterministic key generation
2//!
3//! > <div class="warning">
4//! >
5//! > **Warning**
6//! >
7//! > `slip-10` crate has been restructured and renamed into
8//! > [`hd-wallet`](https://crates.io/crates/hd-wallet). `slip-10` is not likely
9//! > to receive any future updates. Please, consider switching to successor library.
10//! >
11//! > In order to migrate to the successor `hd-wallet v0.5`, include it into Cargo.toml:
12//! > ```toml
13//! > hd-wallet = "0.5"
14//! > ```
15//! >
16//! > Then you'll need to change `slip_10::` references in your code to `hd_wallet::`. For instance,
17//! > `slip_10::HardenedIndex` becomes `hd_wallet::HardenedIndex`.
18//! >
19//! > The functions for child wallet derivation has been moved. Derivation algorithm that is used
20//! > in `slip_10` crate corresponds to `hd_wallet::slip10_like`. E.g. if you were deriving a child
21//! > key using `slip_10::derive_child_public_key`, now you need to use `hd_wallet::slip10_like::derive_child_public_key`
22//! > instead.
23//! >
24//! > If you have any problems with migration, don't hesitate to reach out to us [in Discord `#lockness` room](https://discordapp.com/channels/905194001349627914/1294284489635139585).
25//! >
26//! > </div>
27//!
28//! [SLIP10][slip10-spec] is a specification for implementing HD wallets. It aims at supporting many
29//! curves while being compatible with [BIP32][bip32-spec].
30//!
31//! The implementation is based on [generic-ec](generic_ec) library that provides generic
32//! elliptic curve arithmetic. The crate is `no_std` and `no_alloc` friendly.
33//!
34//! ### Curves support
35//! Implementation currently does not support ed25519 curve. All other curves are
36//! supported: both secp256k1 and secp256r1. In fact, implementation may work with any
37//! curve, but only those are covered by the SLIP10 specs.
38//!
39//! The crate also re-exports supported curves in [supported_curves] module (requires
40//! enabling a feature), but any other curve implementation will work with the crate.
41//!
42//! ### Features
43//! * `std`: enables std library support (mainly, it just implements [`Error`](std::error::Error)
44//!   trait for the error types)
45//! * `curve-secp256k1` and `curve-secp256r1` add curve implementation into the crate [supported_curves]
46//!   module
47//!
48//! ### Examples
49//!
50//! Derive a master key from the seed, and then derive a child key m/1<sub>H</sub>/10:
51//! ```rust
52//! use slip_10::supported_curves::Secp256k1;
53//!
54//! let seed = b"16-64 bytes of high entropy".as_slice();
55//! let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
56//! let master_key_pair = slip_10::ExtendedKeyPair::from(master_key);
57//!
58//! let child_key_pair = slip_10::derive_child_key_pair_with_path(
59//!     &master_key_pair,
60//!     [1 + slip_10::H, 10],
61//! );
62//! # Ok::<(), Box<dyn std::error::Error>>(())
63//! ```
64//!
65//! [slip10-spec]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md
66//! [bip32-spec]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
67
68#![cfg_attr(not(feature = "std"), no_std)]
69#![forbid(missing_docs, unsafe_code)]
70
71use core::ops;
72
73use generic_array::{
74    typenum::{U32, U64},
75    GenericArray,
76};
77use generic_ec::{Curve, Point, Scalar, SecretScalar};
78use hmac::Mac as _;
79
80#[cfg(any(
81    feature = "curve-secp256k1",
82    feature = "curve-secp256r1",
83    feature = "all-curves"
84))]
85pub use generic_ec::curves as supported_curves;
86
87pub mod errors;
88
89type HmacSha512 = hmac::Hmac<sha2::Sha512>;
90/// Beggining of hardened child indexes
91///
92/// $H = 2^{31}$ defines the range of hardened indexes. All indexes $i$ such that $H \le i$ are hardened.
93///
94/// ## Example
95/// Derive a child key with a path m/1<sub>H</sub>
96/// ```rust
97/// use slip_10::supported_curves::Secp256k1;
98///
99/// # let seed = b"do not use this seed in prod :)".as_slice();
100/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
101/// let master_key_pair = slip_10::ExtendedKeyPair::from(master_key);
102///
103/// let hardened_child = slip_10::derive_child_key_pair(
104///     &master_key_pair,
105///     1 + slip_10::H,
106/// );
107/// #
108/// # Ok::<(), slip_10::errors::InvalidLength>(())
109/// ```
110pub const H: u32 = 1 << 31;
111
112/// Child index, whether hardened or not
113#[derive(Clone, Copy, Debug)]
114#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "u32"))]
115#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(from = "u32"))]
116pub enum ChildIndex {
117    /// Hardened index
118    Hardened(HardenedIndex),
119    /// Non-hardened index
120    NonHardened(NonHardenedIndex),
121}
122
123/// Child index in range $2^{31} \le i < 2^{32}$ corresponing to a hardened wallet
124#[derive(Clone, Copy, Debug)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "u32"))]
126#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(try_from = "u32"))]
127pub struct HardenedIndex(u32);
128
129/// Child index in range $0 \le i < 2^{31}$ corresponing to a non-hardened wallet
130#[derive(Clone, Copy, Debug)]
131#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "u32"))]
132#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(try_from = "u32"))]
133pub struct NonHardenedIndex(u32);
134
135/// Extended public key
136#[derive(Clone, Copy, Debug)]
137#[cfg_attr(
138    feature = "serde",
139    derive(serde::Serialize, serde::Deserialize),
140    serde(bound = "")
141)]
142pub struct ExtendedPublicKey<E: Curve> {
143    /// The public key that can be used for signature verification
144    pub public_key: Point<E>,
145    /// A chain code that is used to derive child keys
146    pub chain_code: ChainCode,
147}
148
149/// Extended secret key
150#[derive(Clone, Debug)]
151#[cfg_attr(
152    feature = "serde",
153    derive(serde::Serialize, serde::Deserialize),
154    serde(bound = "")
155)]
156pub struct ExtendedSecretKey<E: Curve> {
157    /// The secret key that can be used for signing
158    pub secret_key: SecretScalar<E>,
159    /// A chain code that is used to derive child keys
160    pub chain_code: ChainCode,
161}
162
163/// Pair of extended secret and public keys
164#[derive(Clone, Debug)]
165pub struct ExtendedKeyPair<E: Curve> {
166    public_key: ExtendedPublicKey<E>,
167    secret_key: ExtendedSecretKey<E>,
168}
169
170/// A shift that can be applied to parent key to obtain a child key
171///
172/// It contains an already derived child public key as it needs to be derived
173/// in process of calculating the shift value
174#[derive(Clone, Copy, Debug)]
175#[cfg_attr(
176    feature = "serde",
177    derive(serde::Serialize, serde::Deserialize),
178    serde(bound = "")
179)]
180pub struct DerivedShift<E: Curve> {
181    /// Derived shift
182    pub shift: Scalar<E>,
183    /// Derived child extended public key
184    pub child_public_key: ExtendedPublicKey<E>,
185}
186
187/// Chain code of extended key as defined in SLIP-10
188pub type ChainCode = [u8; 32];
189
190impl HardenedIndex {
191    /// The smallest possible value of hardened index. Equals to $2^{31}$
192    pub const MIN: Self = Self(H);
193    /// The largest possible value of hardened index. Equals to $2^{32} - 1$
194    pub const MAX: Self = Self(u32::MAX);
195}
196impl NonHardenedIndex {
197    /// The smallest possible value of non-hardened index. Equals to $0$
198    pub const MIN: Self = Self(0);
199    /// The largest possible value of non-hardened index. Equals to $2^{31} - 1$
200    pub const MAX: Self = Self(H - 1);
201}
202impl ops::Deref for HardenedIndex {
203    type Target = u32;
204    fn deref(&self) -> &Self::Target {
205        &self.0
206    }
207}
208impl ops::Deref for NonHardenedIndex {
209    type Target = u32;
210    fn deref(&self) -> &Self::Target {
211        &self.0
212    }
213}
214impl ops::Deref for ChildIndex {
215    type Target = u32;
216    fn deref(&self) -> &Self::Target {
217        match self {
218            Self::Hardened(i) => i,
219            Self::NonHardened(i) => i,
220        }
221    }
222}
223impl From<u32> for ChildIndex {
224    fn from(value: u32) -> Self {
225        match value {
226            H.. => Self::Hardened(HardenedIndex(value)),
227            _ => Self::NonHardened(NonHardenedIndex(value)),
228        }
229    }
230}
231impl TryFrom<u32> for HardenedIndex {
232    type Error = errors::OutOfRange;
233    fn try_from(value: u32) -> Result<Self, Self::Error> {
234        match ChildIndex::from(value) {
235            ChildIndex::Hardened(v) => Ok(v),
236            _ => Err(errors::OutOfRange),
237        }
238    }
239}
240impl TryFrom<u32> for NonHardenedIndex {
241    type Error = errors::OutOfRange;
242    fn try_from(value: u32) -> Result<Self, Self::Error> {
243        match ChildIndex::from(value) {
244            ChildIndex::NonHardened(v) => Ok(v),
245            _ => Err(errors::OutOfRange),
246        }
247    }
248}
249impl From<ChildIndex> for u32 {
250    fn from(value: ChildIndex) -> Self {
251        match value {
252            ChildIndex::Hardened(v) => v.0,
253            ChildIndex::NonHardened(v) => v.0,
254        }
255    }
256}
257impl From<HardenedIndex> for u32 {
258    fn from(value: HardenedIndex) -> Self {
259        value.0
260    }
261}
262impl From<NonHardenedIndex> for u32 {
263    fn from(value: NonHardenedIndex) -> Self {
264        value.0
265    }
266}
267impl core::str::FromStr for ChildIndex {
268    type Err = core::num::ParseIntError;
269    fn from_str(s: &str) -> Result<Self, Self::Err> {
270        s.parse::<u32>().map(Into::into)
271    }
272}
273impl core::str::FromStr for HardenedIndex {
274    type Err = errors::ParseChildIndexError;
275    fn from_str(s: &str) -> Result<Self, Self::Err> {
276        let index = s
277            .parse::<u32>()
278            .map_err(errors::ParseChildIndexError::ParseInt)?;
279        HardenedIndex::try_from(index).map_err(errors::ParseChildIndexError::IndexNotInRange)
280    }
281}
282impl core::str::FromStr for NonHardenedIndex {
283    type Err = errors::ParseChildIndexError;
284    fn from_str(s: &str) -> Result<Self, Self::Err> {
285        let index = s
286            .parse::<u32>()
287            .map_err(errors::ParseChildIndexError::ParseInt)?;
288        NonHardenedIndex::try_from(index).map_err(errors::ParseChildIndexError::IndexNotInRange)
289    }
290}
291
292impl<E: Curve> From<&ExtendedSecretKey<E>> for ExtendedPublicKey<E> {
293    fn from(sk: &ExtendedSecretKey<E>) -> Self {
294        ExtendedPublicKey {
295            public_key: Point::generator() * &sk.secret_key,
296            chain_code: sk.chain_code,
297        }
298    }
299}
300
301impl<E: Curve> From<ExtendedSecretKey<E>> for ExtendedKeyPair<E> {
302    fn from(secret_key: ExtendedSecretKey<E>) -> Self {
303        Self {
304            public_key: (&secret_key).into(),
305            secret_key,
306        }
307    }
308}
309
310impl<E: Curve> ExtendedKeyPair<E> {
311    /// Returns chain code of the key
312    pub fn chain_code(&self) -> &ChainCode {
313        debug_assert_eq!(self.public_key.chain_code, self.secret_key.chain_code);
314        &self.public_key.chain_code
315    }
316
317    /// Returns extended public key
318    pub fn public_key(&self) -> &ExtendedPublicKey<E> {
319        &self.public_key
320    }
321
322    /// Returns extended secret key
323    pub fn secret_key(&self) -> &ExtendedSecretKey<E> {
324        &self.secret_key
325    }
326}
327
328#[cfg(feature = "serde")]
329impl<E: Curve> serde::Serialize for ExtendedKeyPair<E> {
330    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
331    where
332        S: serde::Serializer,
333    {
334        self.secret_key.serialize(serializer)
335    }
336}
337
338#[cfg(feature = "serde")]
339impl<'de, E: Curve> serde::Deserialize<'de> for ExtendedKeyPair<E> {
340    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
341    where
342        D: serde::Deserializer<'de>,
343    {
344        let secret_key = ExtendedSecretKey::<E>::deserialize(deserializer)?;
345        Ok(secret_key.into())
346    }
347}
348
349/// Marker for a curve supported by SLIP10 specs and this library
350///
351/// Only implement this trait for the curves that are supported by SLIP10 specs.
352/// Curves provided by the crate out-of-box in [supported_curves] module already
353/// implement this trait.
354pub trait SupportedCurve {
355    /// Specifies which curve it is
356    const CURVE_TYPE: CurveType;
357}
358#[cfg(feature = "curve-secp256k1")]
359impl SupportedCurve for supported_curves::Secp256k1 {
360    const CURVE_TYPE: CurveType = CurveType::Secp256k1;
361}
362#[cfg(feature = "curve-secp256r1")]
363impl SupportedCurve for supported_curves::Secp256r1 {
364    const CURVE_TYPE: CurveType = CurveType::Secp256r1;
365}
366
367/// Curves supported by SLIP-10 spec
368///
369/// It's either secp256k1 or secp256r1. Note that SLIP-10 also supports ed25519 curve, but this library
370/// does not support it.
371///
372/// `CurveType` is only needed for master key derivation.
373#[derive(Clone, Copy, Debug)]
374pub enum CurveType {
375    /// Secp256k1 curve
376    Secp256k1,
377    /// Secp256r1 curve
378    Secp256r1,
379}
380
381/// Derives a master key from the seed
382///
383/// Seed must be 16-64 bytes long, otherwise an error is returned
384pub fn derive_master_key<E: Curve + SupportedCurve>(
385    seed: &[u8],
386) -> Result<ExtendedSecretKey<E>, errors::InvalidLength> {
387    let curve_tag = match E::CURVE_TYPE {
388        CurveType::Secp256k1 => "Bitcoin seed",
389        CurveType::Secp256r1 => "Nist256p1 seed",
390    };
391    derive_master_key_with_curve_tag(curve_tag.as_bytes(), seed)
392}
393
394/// Derives a master key from the seed and the curve tag as defined in SLIP10
395///
396/// It's preferred to use [derive_master_key] instead, as it automatically infers
397/// the curve tag for supported curves. The curve tag is not validated by the function,
398/// it's caller's responsibility to make sure that it complies with SLIP10.
399///
400/// Seed must be 16-64 bytes long, otherwise an error is returned
401pub fn derive_master_key_with_curve_tag<E: Curve>(
402    curve_tag: &[u8],
403    seed: &[u8],
404) -> Result<ExtendedSecretKey<E>, errors::InvalidLength> {
405    if !(16 <= seed.len() && seed.len() <= 64) {
406        return Err(errors::InvalidLength);
407    }
408
409    let hmac = HmacSha512::new_from_slice(curve_tag)
410        .expect("this never fails: hmac can handle keys of any size");
411    let mut i = hmac.clone().chain_update(seed).finalize().into_bytes();
412
413    loop {
414        let (i_left, i_right) = split_into_two_halfes(&i);
415
416        if let Ok(mut sk) = Scalar::<E>::from_be_bytes(i_left) {
417            if !bool::from(subtle::ConstantTimeEq::ct_eq(&sk, &Scalar::zero())) {
418                return Ok(ExtendedSecretKey {
419                    secret_key: SecretScalar::new(&mut sk),
420                    chain_code: (*i_right).into(),
421                });
422            }
423        }
424
425        i = hmac.clone().chain_update(&i[..]).finalize().into_bytes()
426    }
427}
428
429/// Derives child key pair (extended secret key + public key) from parent key pair
430///
431/// ### Example
432/// Derive child key m/1<sub>H</sub> from master key
433/// ```rust
434/// use slip_10::supported_curves::Secp256k1;
435///
436/// # let seed = b"do not use this seed :)".as_slice();
437/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
438/// let master_key_pair = slip_10::ExtendedKeyPair::from(master_key);
439///
440/// let derived_key = slip_10::derive_child_key_pair(
441///     &master_key_pair,
442///     1 + slip_10::H,
443/// );
444/// # Ok::<(), Box<dyn std::error::Error>>(())
445/// ```
446pub fn derive_child_key_pair<E: Curve>(
447    parent_key: &ExtendedKeyPair<E>,
448    child_index: impl Into<ChildIndex>,
449) -> ExtendedKeyPair<E> {
450    let child_index = child_index.into();
451    let shift = match child_index {
452        ChildIndex::Hardened(i) => derive_hardened_shift(parent_key, i),
453        ChildIndex::NonHardened(i) => derive_public_shift(&parent_key.public_key, i),
454    };
455    let mut child_sk = &parent_key.secret_key.secret_key + shift.shift;
456    let child_sk = SecretScalar::new(&mut child_sk);
457    ExtendedKeyPair {
458        secret_key: ExtendedSecretKey {
459            secret_key: child_sk,
460            chain_code: shift.child_public_key.chain_code,
461        },
462        public_key: shift.child_public_key,
463    }
464}
465
466/// Derives a child key pair with specified derivation path from parent key pair
467///
468/// Derivation path is an iterator that yields child indexes.
469///
470/// If derivation path is empty, `parent_key` is returned
471///
472/// ### Example
473/// Derive a child key with path m/1/10/1<sub>H</sub>
474/// ```rust
475/// use slip_10::supported_curves::Secp256k1;
476/// # let seed = b"16-64 bytes of high entropy".as_slice();
477/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
478/// let master_key_pair = slip_10::ExtendedKeyPair::from(master_key);
479///
480/// let child_key = slip_10::derive_child_key_pair_with_path(
481///     &master_key_pair,
482///     [1, 10, 1 + slip_10::H],
483/// );
484/// # Ok::<(), Box<dyn std::error::Error>>(())
485/// ```
486pub fn derive_child_key_pair_with_path<E: Curve>(
487    parent_key: &ExtendedKeyPair<E>,
488    path: impl IntoIterator<Item = impl Into<ChildIndex>>,
489) -> ExtendedKeyPair<E> {
490    let result = try_derive_child_key_pair_with_path(
491        parent_key,
492        path.into_iter().map(Ok::<_, core::convert::Infallible>),
493    );
494    match result {
495        Ok(key) => key,
496        Err(err) => match err {},
497    }
498}
499
500/// Derives a child key pair with specified derivation path from parent key pair
501///
502/// Derivation path is a fallible iterator that yields child indexes. If iterator
503/// yields an error, it's propagated to the caller.
504///
505/// ### Example
506/// Parse a path from the string and derive a child without extra allocations:
507/// ```rust
508/// use slip_10::supported_curves::Secp256k1;
509/// # let seed = b"16-64 bytes of high entropy".as_slice();
510/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
511/// let master_key_pair = slip_10::ExtendedKeyPair::from(master_key);
512///
513/// let path = "1/10/2";
514/// let child_indexes = path.split('/').map(str::parse::<u32>);
515/// let child_key = slip_10::try_derive_child_key_pair_with_path(
516///     &master_key_pair,
517///     child_indexes,
518/// )?;
519/// # Ok::<_, Box<dyn std::error::Error>>(())
520/// ```
521pub fn try_derive_child_key_pair_with_path<E: Curve, Err>(
522    parent_key: &ExtendedKeyPair<E>,
523    path: impl IntoIterator<Item = Result<impl Into<ChildIndex>, Err>>,
524) -> Result<ExtendedKeyPair<E>, Err> {
525    let mut derived_key = parent_key.clone();
526    for child_index in path {
527        derived_key = derive_child_key_pair(&derived_key, child_index?);
528    }
529    Ok(derived_key)
530}
531
532/// Derives child extended public key from parent extended public key
533///
534/// ### Example
535/// Derive a master public key m/1
536/// ```rust
537/// use slip_10::supported_curves::Secp256k1;
538///
539/// # let seed = b"do not use this seed :)".as_slice();
540/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
541/// let master_public_key = slip_10::ExtendedPublicKey::from(&master_key);
542///
543/// let derived_key = slip_10::derive_child_public_key(
544///     &master_public_key,
545///     1.try_into()?,
546/// );
547/// # Ok::<(), Box<dyn std::error::Error>>(())
548/// ```
549pub fn derive_child_public_key<E: Curve>(
550    parent_public_key: &ExtendedPublicKey<E>,
551    child_index: NonHardenedIndex,
552) -> ExtendedPublicKey<E> {
553    derive_public_shift(parent_public_key, child_index).child_public_key
554}
555
556/// Derives a child public key with specified derivation path
557///
558/// Derivation path is an iterator that yields child indexes.
559///
560/// If derivation path is empty, `parent_public_key` is returned
561///
562/// ### Example
563/// Derive a child key with path m/1/10
564/// ```rust
565/// use slip_10::supported_curves::Secp256k1;
566/// # let seed = b"16-64 bytes of high entropy".as_slice();
567/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
568/// let master_public_key = slip_10::ExtendedPublicKey::from(&master_key);
569///
570/// let child_key = slip_10::derive_child_public_key_with_path(
571///     &master_public_key,
572///     [1.try_into()?, 10.try_into()?],
573/// );
574/// # Ok::<(), Box<dyn std::error::Error>>(())
575/// ```
576pub fn derive_child_public_key_with_path<E: Curve>(
577    parent_public_key: &ExtendedPublicKey<E>,
578    path: impl IntoIterator<Item = NonHardenedIndex>,
579) -> ExtendedPublicKey<E> {
580    let result = try_derive_child_public_key_with_path(
581        parent_public_key,
582        path.into_iter().map(Ok::<_, core::convert::Infallible>),
583    );
584    match result {
585        Ok(key) => key,
586        Err(err) => match err {},
587    }
588}
589
590/// Derives a child public key with specified derivation path
591///
592/// Derivation path is a fallible iterator that yields child indexes. If iterator
593/// yields an error, it's propagated to the caller.
594///
595/// ### Example
596/// Parse a path from the string and derive a child without extra allocations:
597/// ```rust
598/// use slip_10::supported_curves::Secp256k1;
599/// # let seed = b"16-64 bytes of high entropy".as_slice();
600/// let master_key = slip_10::derive_master_key::<Secp256k1>(seed)?;
601/// let master_public_key = slip_10::ExtendedPublicKey::from(&master_key);
602///
603/// let path = "1/10/2";
604/// let child_indexes = path.split('/').map(str::parse);
605/// let child_key = slip_10::try_derive_child_public_key_with_path(
606///     &master_public_key,
607///     child_indexes,
608/// )?;
609/// # Ok::<_, Box<dyn std::error::Error>>(())
610/// ```
611pub fn try_derive_child_public_key_with_path<E: Curve, Err>(
612    parent_public_key: &ExtendedPublicKey<E>,
613    path: impl IntoIterator<Item = Result<NonHardenedIndex, Err>>,
614) -> Result<ExtendedPublicKey<E>, Err> {
615    let mut derived_key = *parent_public_key;
616    for child_index in path {
617        derived_key = derive_child_public_key(&derived_key, child_index?);
618    }
619    Ok(derived_key)
620}
621
622/// Derive a shift for hardened child
623pub fn derive_hardened_shift<E: Curve>(
624    parent_key: &ExtendedKeyPair<E>,
625    child_index: HardenedIndex,
626) -> DerivedShift<E> {
627    let hmac = HmacSha512::new_from_slice(parent_key.chain_code())
628        .expect("this never fails: hmac can handle keys of any size");
629    let i = hmac
630        .clone()
631        .chain_update([0x00])
632        .chain_update(parent_key.secret_key.secret_key.as_ref().to_be_bytes())
633        .chain_update(child_index.to_be_bytes())
634        .finalize()
635        .into_bytes();
636    calculate_shift(&hmac, &parent_key.public_key, *child_index, i)
637}
638
639/// Derives a shift for non-hardened child
640pub fn derive_public_shift<E: Curve>(
641    parent_public_key: &ExtendedPublicKey<E>,
642    child_index: NonHardenedIndex,
643) -> DerivedShift<E> {
644    let hmac = HmacSha512::new_from_slice(&parent_public_key.chain_code)
645        .expect("this never fails: hmac can handle keys of any size");
646    let i = hmac
647        .clone()
648        .chain_update(&parent_public_key.public_key.to_bytes(true))
649        .chain_update(child_index.to_be_bytes())
650        .finalize()
651        .into_bytes();
652    calculate_shift(&hmac, parent_public_key, *child_index, i)
653}
654
655fn calculate_shift<E: Curve>(
656    hmac: &HmacSha512,
657    parent_public_key: &ExtendedPublicKey<E>,
658    child_index: u32,
659    mut i: hmac::digest::Output<HmacSha512>,
660) -> DerivedShift<E> {
661    loop {
662        let (i_left, i_right) = split_into_two_halfes(&i);
663
664        if let Ok(shift) = Scalar::<E>::from_be_bytes(i_left) {
665            let child_pk = parent_public_key.public_key + Point::generator() * shift;
666            if !child_pk.is_zero() {
667                return DerivedShift {
668                    shift,
669                    child_public_key: ExtendedPublicKey {
670                        public_key: child_pk,
671                        chain_code: (*i_right).into(),
672                    },
673                };
674            }
675        }
676
677        i = hmac
678            .clone()
679            .chain_update([0x01])
680            .chain_update(i_right)
681            .chain_update(child_index.to_be_bytes())
682            .finalize()
683            .into_bytes()
684    }
685}
686
687/// Splits array `I` of 64 bytes into two arrays `I_L = I[..32]` and `I_R = I[32..]`
688fn split_into_two_halfes(
689    i: &GenericArray<u8, U64>,
690) -> (&GenericArray<u8, U32>, &GenericArray<u8, U32>) {
691    generic_array::sequence::Split::split(i)
692}