Skip to main content

kaspa_bip32/
xpublic_key.rs

1//! Extended public keys
2//!
3use crate::{
4    ChildNumber, DerivationPath, Error, ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey, KEY_SIZE, KeyFingerprint, Prefix,
5    PrivateKey, PublicKey, PublicKeyBytes, Result, types::*,
6};
7use borsh::{BorshDeserialize, BorshSerialize};
8use core::str::FromStr;
9use hmac::Mac;
10use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
11use std::fmt;
12
13///// Extended public secp256k1 ECDSA verification key.
14//#[cfg(feature = "secp256k1")]
15//#[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
16//pub type XPub = ExtendedPublicKey<k256::ecdsa::VerifyingKey>;
17
18/// Extended public keys derived using BIP32.
19///
20/// Generic around a [`PublicKey`] type.
21#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
22pub struct ExtendedPublicKey<K: PublicKey> {
23    /// Derived public key
24    pub public_key: K,
25
26    /// Extended key attributes.
27    pub attrs: ExtendedKeyAttrs,
28}
29
30#[allow(dead_code)]
31impl<K> ExtendedPublicKey<K>
32where
33    K: PublicKey,
34{
35    /// Obtain the non-extended public key value `K`.
36    pub fn public_key(&self) -> &K {
37        &self.public_key
38    }
39
40    /// Get attributes for this key such as depth, parent fingerprint,
41    /// child number, and chain code.
42    pub fn attrs(&self) -> &ExtendedKeyAttrs {
43        &self.attrs
44    }
45
46    /// Compute a 4-byte key fingerprint for this extended public key.
47    pub fn fingerprint(&self) -> KeyFingerprint {
48        self.public_key().fingerprint()
49    }
50
51    /// Derive a child key for a particular [`ChildNumber`].
52    pub fn derive_child(&self, child_number: ChildNumber) -> Result<Self> {
53        if child_number.is_hardened() {
54            // Cannot derive child public keys for hardened `ChildNumber`s
55            return Err(Error::ChildNumber);
56        }
57
58        let depth = self.attrs.depth.checked_add(1).ok_or(Error::Depth)?;
59
60        let mut hmac = HmacSha512::new_from_slice(&self.attrs.chain_code).map_err(Error::Hmac)?;
61
62        hmac.update(&self.public_key.to_bytes());
63        hmac.update(&child_number.to_bytes());
64
65        let result = hmac.finalize().into_bytes();
66        let (child_key, chain_code) = result.split_at(KEY_SIZE);
67        let public_key = self.public_key.derive_child(child_key.try_into()?)?;
68
69        let attrs = ExtendedKeyAttrs {
70            parent_fingerprint: self.public_key.fingerprint(),
71            child_number,
72            chain_code: chain_code.try_into()?,
73            depth,
74        };
75
76        Ok(ExtendedPublicKey { public_key, attrs })
77    }
78
79    pub fn derive_path(self, path: &DerivationPath) -> Result<Self> {
80        path.iter().try_fold(self, |key, child_num| key.derive_child(child_num))
81    }
82
83    /// Serialize the raw public key as a byte array (e.g. SEC1-encoded).
84    pub fn to_bytes(&self) -> PublicKeyBytes {
85        self.public_key.to_bytes()
86    }
87
88    /// Serialize this key as an [`ExtendedKey`].
89    pub fn to_extended_key(&self, prefix: Prefix) -> ExtendedKey {
90        ExtendedKey { prefix, attrs: self.attrs.clone(), key_bytes: self.to_bytes() }
91    }
92
93    pub fn to_string(&self, prefix: Option<Prefix>) -> String {
94        let prefix = prefix.unwrap_or(Prefix::XPUB);
95        self.to_extended_key(prefix).to_string()
96    }
97
98    pub fn from_public_key(public_key: K, attrs: &ExtendedKeyAttrs) -> Self {
99        ExtendedPublicKey { public_key, attrs: attrs.clone() }
100    }
101}
102
103impl<K> From<&ExtendedPrivateKey<K>> for ExtendedPublicKey<K::PublicKey>
104where
105    K: PrivateKey,
106{
107    fn from(xprv: &ExtendedPrivateKey<K>) -> ExtendedPublicKey<K::PublicKey> {
108        ExtendedPublicKey { public_key: xprv.private_key().public_key(), attrs: xprv.attrs().clone() }
109    }
110}
111
112impl<K> FromStr for ExtendedPublicKey<K>
113where
114    K: PublicKey,
115{
116    type Err = Error;
117
118    fn from_str(xpub: &str) -> Result<Self> {
119        ExtendedKey::from_str(xpub)?.try_into()
120    }
121}
122
123impl<K> TryFrom<ExtendedKey> for ExtendedPublicKey<K>
124where
125    K: PublicKey,
126{
127    type Error = Error;
128
129    fn try_from(extended_key: ExtendedKey) -> Result<ExtendedPublicKey<K>> {
130        if extended_key.prefix.is_public() {
131            Ok(ExtendedPublicKey { public_key: PublicKey::from_bytes(extended_key.key_bytes)?, attrs: extended_key.attrs.clone() })
132        } else {
133            Err(Error::Crypto(secp256k1::Error::InvalidPublicKey))
134        }
135    }
136}
137
138impl fmt::Display for ExtendedPublicKey<secp256k1::PublicKey> {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        self.to_string(None).fmt(f)
141    }
142}
143
144impl<K> ExtendedPublicKey<K>
145where
146    K: PublicKey,
147{
148    // a unique number used for binary
149    // serialization data alignment check
150    const STORAGE_MAGIC: u16 = 0x4b58;
151    // binary serialization version
152    const STORAGE_VERSION: u16 = 0;
153}
154
155#[derive(BorshSerialize, BorshDeserialize)]
156struct Header {
157    magic: u16,
158    version: u16,
159}
160
161impl<K> BorshSerialize for ExtendedPublicKey<K>
162where
163    K: PublicKey,
164{
165    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
166        Header { version: Self::STORAGE_VERSION, magic: Self::STORAGE_MAGIC }.serialize(writer)?;
167        writer.write_all(self.public_key.to_bytes().as_slice())?;
168        BorshSerialize::serialize(&self.attrs, writer)?;
169        Ok(())
170    }
171}
172
173impl<K> BorshDeserialize for ExtendedPublicKey<K>
174where
175    K: PublicKey,
176{
177    fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
178        let Header { version, magic } = Header::deserialize_reader(reader)?;
179        if magic != Self::STORAGE_MAGIC {
180            return Err(std::io::Error::other("Invalid extended public key magic value"));
181        }
182        if version != Self::STORAGE_VERSION {
183            return Err(std::io::Error::other("Invalid extended public key version"));
184        }
185
186        let mut public_key_bytes: [u8; KEY_SIZE + 1] = [0; KEY_SIZE + 1];
187        reader.read_exact(&mut public_key_bytes)?;
188        let public_key = K::from_bytes(public_key_bytes).map_err(|_| std::io::Error::other("Invalid extended public key"))?;
189        let attrs = ExtendedKeyAttrs::deserialize_reader(reader)?;
190        Ok(Self { public_key, attrs })
191    }
192}
193
194impl<K> Serialize for ExtendedPublicKey<K>
195where
196    K: Serialize + PublicKey,
197{
198    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
199    where
200        S: Serializer,
201    {
202        serializer.serialize_str(&self.to_string(None))
203    }
204}
205
206struct ExtendedPublicKeyVisitor<'de, K>
207where
208    K: Deserialize<'de> + PublicKey,
209{
210    phantom: std::marker::PhantomData<&'de K>,
211}
212
213impl<'de, K> de::Visitor<'de> for ExtendedPublicKeyVisitor<'de, K>
214where
215    K: Deserialize<'de> + PublicKey,
216{
217    type Value = ExtendedPublicKey<K>;
218
219    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
220        formatter.write_str("a string containing network_type and optional suffix separated by a '-'")
221    }
222
223    fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
224    where
225        E: de::Error,
226    {
227        ExtendedPublicKey::<K>::from_str(value).map_err(|err| de::Error::custom(err.to_string()))
228    }
229}
230
231impl<'de, K> Deserialize<'de> for ExtendedPublicKey<K>
232where
233    K: Deserialize<'de> + PublicKey + 'de,
234{
235    fn deserialize<D>(deserializer: D) -> std::result::Result<ExtendedPublicKey<K>, D::Error>
236    where
237        D: Deserializer<'de>,
238    {
239        deserializer.deserialize_str(ExtendedPublicKeyVisitor::<'de, K> { phantom: std::marker::PhantomData::<&'de K> })
240    }
241}