slip10/
path.rs

1use crate::{Error, HARDEND};
2
3use alloc::format;
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::convert::From;
7
8/// A path structure defined by BIP 32.
9#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
10pub struct BIP32Path(pub(crate) Vec<u32>);
11
12impl core::str::FromStr for BIP32Path {
13    type Err = Error;
14
15    /// Create a BIP32Path form string literals.
16    fn from_str(path: &str) -> Result<Self, Self::Err> {
17        let mut paths = Vec::new();
18        let path = path.replace("/", "\n");
19
20        for p in path.lines() {
21            if p != "m" {
22                if p.ends_with('H') || p.ends_with('\'') {
23                    let index: u32 = p[..p.len() - 1].parse().map_err(|_| Error::InvalidIndex)?;
24                    if index < HARDEND {
25                        paths.push(index + HARDEND);
26                    } else {
27                        return Err(Error::InvalidIndex);
28                    }
29                } else {
30                    let index: u32 = p.parse().map_err(|_| Error::InvalidIndex)?;
31                    if index < HARDEND {
32                        paths.push(index);
33                    } else {
34                        return Err(Error::InvalidIndex);
35                    }
36                }
37            }
38        }
39
40        Ok(BIP32Path(paths))
41    }
42}
43
44impl core::fmt::Display for BIP32Path {
45    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46        write!(
47            f,
48            "m/{}",
49            self.0
50                .iter()
51                .map(|index| {
52                    if let Some(index) = index.checked_sub(HARDEND) {
53                        format!("{}'", index)
54                    } else {
55                        format!("{}", index)
56                    }
57                })
58                .collect::<Vec<String>>()
59                .join("/")
60        )
61    }
62}
63
64impl BIP32Path {
65    /// Return the depth of the BIP32Path. For example, "m/0'/0'" will have depth of 2.
66    pub fn depth(&self) -> u8 {
67        self.0.len() as u8
68    }
69
70    /// Return the index value of corresponding depth in the BIP32Path.
71    pub fn index(&self, depth: u8) -> Option<&u32> {
72        self.0.get(depth as usize)
73    }
74
75    /// Push one index to the BIP32Path.
76    pub fn push(&mut self, index: u32) {
77        self.0.push(index);
78    }
79
80    /// Pop last index of the BIP32Path.
81    pub fn pop(&mut self) -> Option<u32> {
82        self.0.pop()
83    }
84}
85
86impl From<Vec<u32>> for BIP32Path {
87    fn from(vector: Vec<u32>) -> Self {
88        BIP32Path(vector)
89    }
90}