bitcoin_hd/
path.rs

1// Wallet-level libraries for bitcoin protocol by LNP/BP Association
2//
3// Written in 2020-2022 by
4//     Dr. Maxim Orlovsky <orlovsky@lnp-bp.org>
5//
6// This software is distributed without any warranty.
7//
8// You should have received a copy of the Apache-2.0 License
9// along with this software.
10// If not, see <https://opensource.org/licenses/Apache-2.0>.
11
12use core::fmt::{self, Display, Formatter};
13use core::str::FromStr;
14use std::borrow::{Borrow, BorrowMut};
15use std::io;
16use std::ops::{Deref, DerefMut};
17
18use bitcoin::util::bip32;
19use strict_encoding::{StrictDecode, StrictEncode};
20
21use crate::SegmentIndexes;
22
23/// Derivation path that consisting only of single type of segments.
24///
25/// Useful in specifying concrete derivation from a provided extended public key
26/// without extended private key accessible.
27///
28/// Type guarantees that the number of derivation path segments is non-zero.
29#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
30#[cfg_attr(
31    feature = "serde",
32    derive(Serialize, Deserialize),
33    serde(crate = "serde_crate")
34)]
35pub struct DerivationSubpath<Segment>(Vec<Segment>)
36where
37    Segment: SegmentIndexes;
38
39// This is needed to get methods line `len()` and `is_empty()` working.
40impl<Segment> Deref for DerivationSubpath<Segment>
41where
42    Segment: SegmentIndexes,
43{
44    type Target = Vec<Segment>;
45
46    fn deref(&self) -> &Self::Target { &self.0 }
47}
48
49impl<Segment> DerefMut for DerivationSubpath<Segment>
50where
51    Segment: SegmentIndexes,
52{
53    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
54}
55
56impl<Segment> Default for DerivationSubpath<Segment>
57where
58    Segment: SegmentIndexes,
59{
60    fn default() -> Self { Self(vec![]) }
61}
62
63impl<Segment> From<&[Segment]> for DerivationSubpath<Segment>
64where
65    Segment: SegmentIndexes,
66{
67    fn from(path: &[Segment]) -> Self { Self(path.to_vec()) }
68}
69
70impl<Segment> AsRef<[Segment]> for DerivationSubpath<Segment>
71where
72    Segment: SegmentIndexes,
73{
74    #[inline]
75    fn as_ref(&self) -> &[Segment] { &self.0 }
76}
77
78impl<Segment> AsMut<Vec<Segment>> for DerivationSubpath<Segment>
79where
80    Segment: SegmentIndexes,
81{
82    #[inline]
83    fn as_mut(&mut self) -> &mut Vec<Segment> { &mut self.0 }
84}
85
86impl<Segment> Borrow<[Segment]> for DerivationSubpath<Segment>
87where
88    Segment: SegmentIndexes,
89{
90    #[inline]
91    fn borrow(&self) -> &[Segment] { &self.0 }
92}
93
94impl<Segment> BorrowMut<[Segment]> for DerivationSubpath<Segment>
95where
96    Segment: SegmentIndexes,
97{
98    #[inline]
99    fn borrow_mut(&mut self) -> &mut [Segment] { &mut self.0 }
100}
101
102impl<Segment> StrictEncode for DerivationSubpath<Segment>
103where
104    Segment: SegmentIndexes + StrictEncode,
105{
106    #[inline]
107    fn strict_encode<E: io::Write>(&self, e: E) -> Result<usize, strict_encoding::Error> {
108        self.0.strict_encode(e)
109    }
110}
111
112impl<Segment> StrictDecode for DerivationSubpath<Segment>
113where
114    Segment: SegmentIndexes + StrictDecode,
115{
116    #[inline]
117    fn strict_decode<D: io::Read>(d: D) -> Result<Self, strict_encoding::Error> {
118        Ok(Self(Vec::strict_decode(d)?))
119    }
120}
121
122impl<Segment> Display for DerivationSubpath<Segment>
123where
124    Segment: SegmentIndexes + Display,
125{
126    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
127        for segment in &self.0 {
128            f.write_str("/")?;
129            Display::fmt(segment, f)?;
130        }
131        Ok(())
132    }
133}
134
135impl<Segment> FromStr for DerivationSubpath<Segment>
136where
137    Segment: SegmentIndexes + FromStr,
138    bip32::Error: From<<Segment as FromStr>::Err>,
139{
140    type Err = bip32::Error;
141
142    fn from_str(s: &str) -> Result<Self, Self::Err> {
143        if !s.starts_with('/') {
144            return Err(bip32::Error::InvalidDerivationPathFormat);
145        }
146        let inner = s[1..]
147            .split('/')
148            .map(Segment::from_str)
149            .collect::<Result<Vec<_>, Segment::Err>>()?;
150        if inner.is_empty() {
151            return Err(bip32::Error::InvalidDerivationPathFormat);
152        }
153        Ok(Self(inner))
154    }
155}
156
157impl<Segment> IntoIterator for DerivationSubpath<Segment>
158where
159    Segment: SegmentIndexes,
160{
161    type Item = Segment;
162    type IntoIter = std::vec::IntoIter<Segment>;
163
164    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
165}
166
167impl<'path, Segment> IntoIterator for &'path DerivationSubpath<Segment>
168where
169    Segment: SegmentIndexes + Copy,
170{
171    type Item = Segment;
172    type IntoIter = std::iter::Copied<std::slice::Iter<'path, Segment>>;
173
174    fn into_iter(self) -> Self::IntoIter { self.0.iter().copied() }
175}
176
177impl<Segment> FromIterator<Segment> for DerivationSubpath<Segment>
178where
179    Segment: SegmentIndexes,
180{
181    fn from_iter<T: IntoIterator<Item = Segment>>(iter: T) -> Self {
182        Self(iter.into_iter().collect())
183    }
184}
185
186impl<Segment> DerivationSubpath<Segment>
187where
188    Segment: SegmentIndexes,
189{
190    /// Constructs empty derivation path.
191    pub fn new() -> Self { Self::default() }
192}