kaspa_bip32/
xpublic_key.rs1use 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#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
22pub struct ExtendedPublicKey<K: PublicKey> {
23 pub public_key: K,
25
26 pub attrs: ExtendedKeyAttrs,
28}
29
30#[allow(dead_code)]
31impl<K> ExtendedPublicKey<K>
32where
33 K: PublicKey,
34{
35 pub fn public_key(&self) -> &K {
37 &self.public_key
38 }
39
40 pub fn attrs(&self) -> &ExtendedKeyAttrs {
43 &self.attrs
44 }
45
46 pub fn fingerprint(&self) -> KeyFingerprint {
48 self.public_key().fingerprint()
49 }
50
51 pub fn derive_child(&self, child_number: ChildNumber) -> Result<Self> {
53 if child_number.is_hardened() {
54 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 pub fn to_bytes(&self) -> PublicKeyBytes {
85 self.public_key.to_bytes()
86 }
87
88 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 const STORAGE_MAGIC: u16 = 0x4b58;
151 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}