1use crate::legacy_address::base58;
13use crate::legacy_address::cbor;
14use cbor_event::{self, cbor, de::Deserializer, se::Serializer};
15use cryptoxide::blake2b::Blake2b;
16use cryptoxide::digest::Digest;
17use cryptoxide::sha3;
18use ed25519_bip32::XPub;
19
20use std::{
21 convert::{TryFrom, TryInto},
22 fmt,
23 io::{BufRead, Write},
24};
25use crate::wasm_bindgen;
26
27#[wasm_bindgen]
28#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
29#[cfg_attr(feature = "generic-serialization", derive(Serialize, Deserialize))]
30pub enum ByronAddressType {
31 ATPubKey,
32 ATScript,
33 ATRedeem,
34}
35impl fmt::Display for ByronAddressType {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match self {
38 ByronAddressType::ATPubKey => write!(f, "Public Key"),
39 ByronAddressType::ATScript => write!(f, "Script"),
40 ByronAddressType::ATRedeem => write!(f, "Redeem"),
41 }
42 }
43}
44impl ByronAddressType {
46 fn from_u64(v: u64) -> Option<Self> {
47 match v {
48 0 => Some(ByronAddressType::ATPubKey),
49 1 => Some(ByronAddressType::ATScript),
50 2 => Some(ByronAddressType::ATRedeem),
51 _ => None,
52 }
53 }
54 fn to_byte(self) -> u8 {
55 match self {
56 ByronAddressType::ATPubKey => 0,
57 ByronAddressType::ATScript => 1,
58 ByronAddressType::ATRedeem => 2,
59 }
60 }
61}
62impl cbor_event::se::Serialize for ByronAddressType {
63 fn serialize<'se, W: Write>(
64 &self,
65 serializer: &'se mut Serializer<W>,
66 ) -> cbor_event::Result<&'se mut Serializer<W>> {
67 serializer.write_unsigned_integer(self.to_byte() as u64)
68 }
69}
70impl cbor_event::de::Deserialize for ByronAddressType {
71 fn deserialize<R: BufRead>(reader: &mut Deserializer<R>) -> cbor_event::Result<Self> {
72 match ByronAddressType::from_u64(reader.unsigned_integer()?) {
73 Some(addr_type) => Ok(addr_type),
74 None => Err(cbor_event::Error::CustomError(format!("Invalid ByronAddressType"))),
75 }
76 }
77}
78
79type HDAddressPayload = Vec<u8>;
80
81#[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
82pub struct Attributes {
83 pub derivation_path: Option<HDAddressPayload>,
84 pub protocol_magic: Option<u32>,
85}
86impl Attributes {
87 pub fn new_bootstrap_era(hdap: Option<HDAddressPayload>, protocol_magic: Option<u32>) -> Self {
88 Attributes {
89 derivation_path: hdap,
90 protocol_magic,
91 }
92 }
93}
94
95const ATTRIBUTE_NAME_TAG_DERIVATION: u64 = 1;
96const ATTRIBUTE_NAME_TAG_PROTOCOL_MAGIC: u64 = 2;
97
98impl cbor_event::se::Serialize for Attributes {
99 fn serialize<'se, W: Write>(
100 &self,
101 serializer: &'se mut Serializer<W>,
102 ) -> cbor_event::Result<&'se mut Serializer<W>> {
103 let mut len = 0;
104 if let Some(_) = &self.derivation_path {
105 len += 1
106 };
107 if let Some(_) = &self.protocol_magic {
108 len += 1
109 };
110 let serializer = serializer.write_map(cbor_event::Len::Len(len))?;
111 let serializer = match &self.derivation_path {
112 &None => serializer,
113 &Some(ref dp) => serializer
114 .write_unsigned_integer(ATTRIBUTE_NAME_TAG_DERIVATION)?
115 .write_bytes(&dp)?,
116 };
117 let serializer = match &self.protocol_magic {
118 &None => serializer,
119 &Some(protocol_magic) => serializer
120 .write_unsigned_integer(ATTRIBUTE_NAME_TAG_PROTOCOL_MAGIC)?
121 .write_bytes(cbor!(&protocol_magic)?)?,
122 };
123 Ok(serializer)
124 }
125}
126impl cbor_event::de::Deserialize for Attributes {
127 fn deserialize<R: BufRead>(reader: &mut Deserializer<R>) -> cbor_event::Result<Self> {
128 let len = reader.map()?;
129 let mut len = match len {
130 cbor_event::Len::Indefinite => {
131 return Err(cbor_event::Error::CustomError(format!(
132 "Invalid Attributes: received map of {:?} elements",
133 len
134 )));
135 }
136 cbor_event::Len::Len(len) => len,
137 };
138 let mut derivation_path = None;
139 let mut protocol_magic = None;
140 while len > 0 {
141 let key = reader.unsigned_integer()?;
142 match key {
143 ATTRIBUTE_NAME_TAG_DERIVATION => derivation_path = Some(reader.bytes()?),
144 ATTRIBUTE_NAME_TAG_PROTOCOL_MAGIC => {
145 let bytes = reader.bytes()?;
147 let n = Deserializer::from(std::io::Cursor::new(bytes)).deserialize::<u32>()?;
148 protocol_magic = Some(n);
149 }
150 _ => {
151 return Err(cbor_event::Error::CustomError(format!(
152 "invalid Attribute key {}",
153 key
154 )));
155 }
156 }
157 len -= 1;
158 }
159 Ok(Attributes {
160 derivation_path,
161 protocol_magic,
162 })
163 }
164}
165
166fn sha3_then_blake2b224(data: &[u8]) -> [u8; 28] {
168 let mut sh3 = sha3::Sha3_256::new();
169 let mut sh3_out = [0; 32];
170 sh3.input(data.as_ref());
171 sh3.result(&mut sh3_out);
172
173 let mut b2b = Blake2b::new(28);
174 let mut out = [0; 28];
175 b2b.input(&sh3_out[..]);
176 b2b.result(&mut out);
177 out
178}
179
180fn hash_spending_data(addr_type: ByronAddressType, xpub: &XPub, attrs: &Attributes) -> [u8; 28] {
181 let buf = cbor!(&(&addr_type, &SpendingData(xpub), attrs))
182 .expect("serialize the HashedSpendingData's digest data");
183 sha3_then_blake2b224(&buf)
184}
185
186#[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
188pub struct Addr(Vec<u8>);
189
190#[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
191pub enum AddressMatchXPub {
192 Yes,
193 No,
194}
195
196impl Addr {
197 pub fn deconstruct(&self) -> ExtendedAddr {
198 let mut raw = Deserializer::from(std::io::Cursor::new(&self.0));
199 cbor_event::de::Deserialize::deserialize(&mut raw).unwrap() }
201
202 pub fn identical_with_pubkey(&self, xpub: &XPub) -> AddressMatchXPub {
204 let ea = self.deconstruct();
205 let newea = ExtendedAddr::new(xpub, ea.attributes);
206 if self == &newea.to_address() {
207 AddressMatchXPub::Yes
208 } else {
209 AddressMatchXPub::No
210 }
211 }
212
213 pub fn identical_with_pubkey_raw(&self, xpub: &[u8]) -> AddressMatchXPub {
215 match XPub::from_slice(xpub) {
216 Ok(xpub) => self.identical_with_pubkey(&xpub),
217 _ => AddressMatchXPub::No,
218 }
219 }
220}
221
222impl AsRef<[u8]> for Addr {
223 fn as_ref(&self) -> &[u8] {
224 self.0.as_ref()
225 }
226}
227
228impl TryFrom<&[u8]> for Addr {
229 type Error = cbor_event::Error;
230
231 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
232 let mut v = Vec::new();
233 {
235 let mut raw = Deserializer::from(std::io::Cursor::new(&slice));
236 let _: ExtendedAddr = cbor_event::de::Deserialize::deserialize(&mut raw)?;
237 }
238 v.extend_from_slice(slice);
239 Ok(Addr(v))
240 }
241}
242
243impl ::std::str::FromStr for Addr {
244 type Err = ParseExtendedAddrError;
245 fn from_str(s: &str) -> Result<Self, Self::Err> {
246 let bytes = base58::decode(s).map_err(ParseExtendedAddrError::Base58Error)?;
247 Self::try_from(&bytes[..]).map_err(ParseExtendedAddrError::EncodingError)
248 }
249}
250
251impl From<ExtendedAddr> for Addr {
252 fn from(ea: ExtendedAddr) -> Self {
253 ea.to_address()
254 }
255}
256
257impl fmt::Display for Addr {
258 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259 write!(f, "{}", base58::encode(&self.0))
260 }
261}
262
263impl cbor_event::se::Serialize for Addr {
264 fn serialize<'se, W: Write>(
265 &self,
266 serializer: &'se mut Serializer<W>,
267 ) -> cbor_event::Result<&'se mut Serializer<W>> {
268 serializer.write_raw_bytes(&self.0)
270 }
271}
272impl cbor_event::de::Deserialize for Addr {
273 fn deserialize<R: BufRead>(reader: &mut Deserializer<R>) -> cbor_event::Result<Self> {
274 let ea: ExtendedAddr = cbor_event::de::Deserialize::deserialize(reader)?;
275 Ok(ea.to_address())
276 }
277}
278
279const EXTENDED_ADDR_LEN: usize = 28;
280
281#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
283pub struct ExtendedAddr {
284 pub addr: [u8; EXTENDED_ADDR_LEN],
285 pub attributes: Attributes,
286 pub addr_type: ByronAddressType,
287}
288impl ExtendedAddr {
289 pub fn new(xpub: &XPub, attrs: Attributes) -> Self {
290 ExtendedAddr {
291 addr: hash_spending_data(ByronAddressType::ATPubKey, xpub, &attrs),
292 attributes: attrs,
293 addr_type: ByronAddressType::ATPubKey,
294 }
295 }
296
297 pub fn new_simple(xpub: &XPub, protocol_magic: Option<u32>) -> Self {
299 ExtendedAddr::new(xpub, Attributes::new_bootstrap_era(None, protocol_magic))
300 }
301
302 pub fn to_address(&self) -> Addr {
303 Addr(cbor!(self).unwrap()) }
305}
306#[derive(Debug)]
307pub enum ParseExtendedAddrError {
308 EncodingError(cbor_event::Error),
309 Base58Error(base58::Error),
310}
311
312impl fmt::Display for ParseExtendedAddrError {
313 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314 use ParseExtendedAddrError::*;
315 match self {
316 EncodingError(_error) => f.write_str("encoding error"),
317 Base58Error(_error) => f.write_str("base58 error"),
318 }
319 }
320}
321
322impl std::error::Error for ParseExtendedAddrError {
323 fn source<'a>(&'a self) -> Option<&'a (dyn std::error::Error + 'static)> {
324 use ParseExtendedAddrError::*;
325 match self {
326 EncodingError(ref error) => Some(error),
327 Base58Error(ref error) => Some(error),
328 }
329 }
330}
331
332impl ::std::str::FromStr for ExtendedAddr {
333 type Err = ParseExtendedAddrError;
334 fn from_str(s: &str) -> Result<Self, Self::Err> {
335 let bytes = base58::decode(s).map_err(ParseExtendedAddrError::Base58Error)?;
336
337 Self::try_from(&bytes[..]).map_err(ParseExtendedAddrError::EncodingError)
338 }
339}
340impl TryFrom<&[u8]> for ExtendedAddr {
341 type Error = cbor_event::Error;
342
343 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
344 let mut raw = Deserializer::from(std::io::Cursor::new(slice));
345 cbor_event::de::Deserialize::deserialize(&mut raw)
346 }
347}
348impl cbor_event::se::Serialize for ExtendedAddr {
349 fn serialize<'se, W: Write>(
350 &self,
351 serializer: &'se mut Serializer<W>,
352 ) -> cbor_event::Result<&'se mut Serializer<W>> {
353 let addr_bytes = cbor_event::Value::Bytes(self.addr.to_vec());
354 cbor::util::encode_with_crc32_(
355 &(&addr_bytes, &self.attributes, &self.addr_type),
356 serializer,
357 )?;
358 Ok(serializer)
359 }
360}
361impl cbor_event::de::Deserialize for ExtendedAddr {
362 fn deserialize<R: BufRead>(reader: &mut Deserializer<R>) -> cbor_event::Result<Self> {
363 let bytes = cbor::util::raw_with_crc32(reader)?;
364 let mut raw = Deserializer::from(std::io::Cursor::new(bytes));
365 raw.tuple(3, "ExtendedAddr")?;
366 let addr_bytes = raw.bytes()?;
367 let addr = addr_bytes.as_slice().try_into().map_err(|_| {
368 cbor_event::Error::WrongLen(
369 addr_bytes.len() as u64,
370 cbor_event::Len::Len(EXTENDED_ADDR_LEN as u64),
371 "invalid extended address length",
372 )
373 })?;
374 let attributes = cbor_event::de::Deserialize::deserialize(&mut raw)?;
375 let addr_type = cbor_event::de::Deserialize::deserialize(&mut raw)?;
376 Ok(ExtendedAddr {
377 addr,
378 addr_type,
379 attributes,
380 })
381 }
382}
383impl fmt::Display for ExtendedAddr {
384 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
385 write!(f, "{}", self.to_address())
386 }
387}
388
389const SPENDING_DATA_TAG_PUBKEY: u64 = 0;
390
391#[derive(Debug, PartialEq, Eq, Clone)]
392pub struct SpendingData<'a>(&'a XPub);
393
394impl<'a> cbor_event::se::Serialize for SpendingData<'a> {
395 fn serialize<'se, W: Write>(
396 &self,
397 serializer: &'se mut Serializer<W>,
398 ) -> cbor_event::Result<&'se mut Serializer<W>> {
399 let ar: [u8; 64] = self.0.clone().into();
400 serializer
401 .write_array(cbor_event::Len::Len(2))?
402 .write_unsigned_integer(SPENDING_DATA_TAG_PUBKEY)?
403 .write_bytes(&ar[..])
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use super::{Addr, AddressMatchXPub};
410 use ed25519_bip32::XPub;
411
412 fn assert_same_address(address: Addr, xpub: XPub) {
413 assert_eq!(
414 address.identical_with_pubkey(&xpub),
415 AddressMatchXPub::Yes,
416 "expected public key {} to match address {}",
417 xpub,
418 address,
419 )
420 }
421
422 #[test]
423 fn test_vector_1() {
424 let address = "DdzFFzCqrhsrcTVhLygT24QwTnNqQqQ8mZrq5jykUzMveU26sxaH529kMpo7VhPrt5pwW3dXeB2k3EEvKcNBRmzCfcQ7dTkyGzTs658C".parse().unwrap();
425 let public_key = XPub::from_bytes([
426 0x6a, 0x50, 0x96, 0x89, 0xc6, 0x53, 0x17, 0x58, 0x65, 0x98, 0x5a, 0xd1, 0xe0, 0xeb,
427 0x5f, 0xf9, 0xad, 0xa6, 0x99, 0x7a, 0xa4, 0x03, 0xe6, 0x48, 0x61, 0x4b, 0x3b, 0x78,
428 0xfc, 0xba, 0x9c, 0x27, 0x30, 0x82, 0x28, 0xd9, 0x87, 0x2a, 0xf8, 0xb6, 0x5b, 0x98,
429 0x7f, 0xf2, 0x3e, 0x1a, 0x20, 0xcd, 0x90, 0xd8, 0x34, 0x6c, 0x31, 0xf0, 0xed, 0xb8,
430 0x99, 0x89, 0x52, 0xdc, 0x67, 0x66, 0x55, 0x80,
431 ]);
432 assert_same_address(address, public_key)
433 }
434
435 #[test]
436 fn test_vector_2() {
437 let address = "DdzFFzCqrht4it4GYgBp4J39FNnKBsPFejSppARXHCf2gGiTJcwXzpRvgDmxPvKQ8aZZmVqcLUz5L66a8Ja46pfKVtFRaKyn9eKdvpaC".parse().unwrap();
438 let public_key = XPub::from_bytes([
439 0xff, 0x7b, 0xf1, 0x29, 0x9d, 0xf3, 0xd7, 0x17, 0x98, 0xae, 0xfd, 0xc4, 0xae, 0xa7,
440 0xdb, 0x2f, 0x8d, 0xb7, 0x60, 0x46, 0x56, 0x94, 0x41, 0xea, 0xe5, 0x8b, 0x72, 0x23,
441 0xb6, 0x8b, 0x44, 0x04, 0x82, 0x15, 0xcb, 0xac, 0x94, 0xbc, 0xb7, 0xf2, 0xcf, 0x33,
442 0x6c, 0x6c, 0x18, 0xbc, 0x3e, 0x71, 0x3f, 0xfd, 0x82, 0x67, 0x59, 0x4f, 0xf6, 0x34,
443 0x93, 0x32, 0xce, 0x4f, 0x98, 0x04, 0xa7, 0xff,
444 ]);
445 assert_same_address(address, public_key)
446 }
447
448 #[test]
449 fn test_vector_3() {
450 let address = "DdzFFzCqrhsvNQtyViTvEdGxfdc5T1E5RorzFWjYodqjhFDy8fQxfDPccmTc4ePbvkiwvRkR8dtqQ1SHpH53fDSoxD17fo9f6WkRjjAA".parse().unwrap();
451 let public_key = XPub::from_bytes([
452 0x5c, 0x36, 0x51, 0xe0, 0xeb, 0x9d, 0x6d, 0xc9, 0x64, 0x07, 0x13, 0x7c, 0xcc, 0x1f,
453 0x37, 0x7a, 0x87, 0x94, 0x61, 0x77, 0xa5, 0x2c, 0xa3, 0x77, 0x2c, 0x6b, 0x4b, 0xeb,
454 0x72, 0x39, 0x50, 0xdc, 0x50, 0x22, 0x46, 0x68, 0x21, 0x8b, 0x8b, 0x36, 0x62, 0x02,
455 0xfe, 0x5b, 0x7d, 0x55, 0x6f, 0x50, 0x1c, 0x5c, 0x4e, 0x2d, 0x58, 0xe0, 0x54, 0x67,
456 0xe1, 0xab, 0xc0, 0x44, 0xc6, 0xc1, 0xbf, 0x8e,
457 ]);
458 assert_same_address(address, public_key)
459 }
460
461 #[test]
462 fn test_vector_4() {
463 let address = "DdzFFzCqrhsn7ZAhKy8mxkzW6G3wryM7K6bH38VAjE2FesJMxia3UviivMvGz146TP1FpDharxTE6nUgCCnZx2fmtKpmxAosg9Tf5b8y".parse().unwrap();
464 let public_key = XPub::from_bytes([
465 0xcd, 0x84, 0x2e, 0x01, 0x0d, 0x81, 0xa6, 0xbe, 0x1e, 0x16, 0x9f, 0xd6, 0x35, 0x21,
466 0xdb, 0xb9, 0x5f, 0x42, 0x41, 0xfc, 0x82, 0x3f, 0x45, 0xb1, 0xcf, 0x1a, 0x1c, 0xb4,
467 0xc5, 0x89, 0x57, 0x27, 0x1d, 0x4d, 0x14, 0x2a, 0x22, 0x94, 0xea, 0x5f, 0xa3, 0x16,
468 0xa4, 0xad, 0xbf, 0xcd, 0x59, 0x7a, 0x7c, 0x89, 0x6a, 0x52, 0xa9, 0xa3, 0xa9, 0xce,
469 0x49, 0x64, 0x4a, 0x10, 0x2d, 0x00, 0x71, 0x99,
470 ]);
471 assert_same_address(address, public_key)
472 }
473
474 #[test]
475 fn test_vector_5() {
476 let address = "DdzFFzCqrhssTCJf4sv664bdQURovAwzx1hNKkMkNLwMNyaxZFuPSDdZTTRMcoDyXHuCiZhbD4umvMJcWGkvFMMzBoBUW5UBdBbDqXGX".parse().unwrap();
477 let public_key = XPub::from_bytes([
478 0x5a, 0xac, 0x2d, 0xd0, 0xa8, 0xdc, 0x5d, 0x61, 0x0a, 0x4b, 0x6f, 0xdf, 0x3f, 0x5e,
479 0xf1, 0xb6, 0x4a, 0xcb, 0x76, 0xb1, 0xe8, 0x1f, 0x6a, 0x35, 0x70, 0x31, 0xfa, 0x19,
480 0xd5, 0xe6, 0x56, 0x9d, 0xcc, 0x37, 0xb7, 0xae, 0x6f, 0x39, 0x15, 0x82, 0xfb, 0x05,
481 0x4b, 0x72, 0xba, 0xda, 0x90, 0xab, 0x14, 0x6c, 0xdd, 0x01, 0x42, 0x0e, 0x4b, 0x40,
482 0x18, 0xf1, 0xa0, 0x55, 0x29, 0x82, 0xd2, 0x31,
483 ]);
484 assert_same_address(address, public_key)
485 }
486
487 #[test]
488 fn test_vector_6() {
489 let address = "DdzFFzCqrhsfi5fFjJUHYPSnfTYrnMohzh3PrrtrVQgwua33HWPKUdTJXo3o77pSGCmDNrjYaAiZmJddaPW9iHyUDatvU2WhX7MgnNMy".parse().unwrap();
490 let public_key = XPub::from_bytes([
491 0x2a, 0x6a, 0xd1, 0x51, 0x09, 0x96, 0xff, 0x2d, 0x10, 0x89, 0xcb, 0x8e, 0xd5, 0xf5,
492 0xc0, 0x61, 0xf6, 0xad, 0x0a, 0xfb, 0xb5, 0x3d, 0x95, 0x40, 0xa0, 0xfc, 0x89, 0xef,
493 0xc0, 0xa2, 0x63, 0xb9, 0x6d, 0xac, 0x00, 0xbd, 0x0d, 0x7b, 0xda, 0x7d, 0x16, 0x3a,
494 0x08, 0xdb, 0x20, 0xba, 0x64, 0xb6, 0x33, 0x4d, 0xca, 0x34, 0xea, 0xc8, 0x2c, 0xf7,
495 0xb4, 0x91, 0xc3, 0x5f, 0x5c, 0xae, 0xc7, 0xb0,
496 ]);
497 assert_same_address(address, public_key)
498 }
499
500 #[test]
501 fn test_vector_7() {
502 let address = "DdzFFzCqrhsy2zYMDQRCF4Nw34C3P7aT5B7JwHFQ6gLAeoHgVXurCLPCm3AeV1nTa1Nd46uDoNt16cnsPFkb4fpLi1J17AmvphCtGFz2".parse().unwrap();
503 let public_key = XPub::from_bytes([
504 0x0c, 0xd2, 0x15, 0x54, 0xa0, 0xf9, 0xb8, 0x25, 0x9c, 0x46, 0x88, 0xdd, 0x00, 0xfc,
505 0x01, 0x88, 0x43, 0x50, 0x79, 0x76, 0x4f, 0xa5, 0x50, 0xfb, 0x57, 0x38, 0x2b, 0xff,
506 0x43, 0xe2, 0xd8, 0xd8, 0x27, 0x27, 0x4e, 0x2a, 0x12, 0x9f, 0x86, 0xc3, 0x80, 0x88,
507 0x34, 0x37, 0x4d, 0xfe, 0x3f, 0xda, 0xa6, 0x28, 0x48, 0x30, 0xb8, 0xf6, 0xe4, 0x0d,
508 0x29, 0x93, 0xde, 0xa2, 0xfb, 0x0a, 0xbe, 0x82,
509 ]);
510 assert_same_address(address, public_key)
511 }
512
513 #[test]
514 fn test_vector_8() {
515 let address = "DdzFFzCqrht8ygB5pLM4uVbS2x4ek2NTDx6R3DJqP7fUaWEkx8RA9UFR8CHitp2R74XLDP876Pe3KLUByHnrWrKWnffpqPpm14rPCxeP".parse().unwrap();
516 let public_key = XPub::from_bytes([
517 0x1f, 0x0a, 0xb8, 0x33, 0xfd, 0xb1, 0xfa, 0x49, 0x58, 0xce, 0x74, 0x04, 0x81, 0x84,
518 0x5b, 0x3a, 0x26, 0x6e, 0xfa, 0xab, 0x2d, 0x65, 0xd1, 0x6b, 0xdd, 0x3d, 0xfe, 0x7f,
519 0xcb, 0xe4, 0x46, 0x30, 0x25, 0x9e, 0xd1, 0x91, 0x98, 0x93, 0x03, 0x9d, 0xfd, 0x40,
520 0x02, 0x4a, 0x72, 0x03, 0x45, 0x5b, 0x03, 0xd6, 0xd0, 0x0d, 0x0a, 0x5c, 0xd6, 0xee,
521 0x82, 0xde, 0x2e, 0xce, 0x73, 0x8a, 0xa1, 0xbf,
522 ]);
523 assert_same_address(address, public_key)
524 }
525
526 #[test]
527 fn test_vector_9() {
528 let address = "DdzFFzCqrhssTywqjv3dw3EakpEydWQcc3phQzR3YF9NPgQN9Ftkx68FfLLnpJ4vhWo9mAjx5EcpM1wNvorSySrpARZGfk5QugHkVs58".parse().unwrap();
529 let public_key = XPub::from_bytes([
530 0x16, 0xf7, 0xd2, 0x55, 0x32, 0x6d, 0x77, 0x6e, 0xc1, 0xb5, 0xed, 0xd2, 0x5f, 0x75,
531 0xd3, 0xe3, 0xeb, 0xe0, 0xb9, 0xd4, 0x9c, 0xdd, 0xb2, 0x46, 0xd8, 0x0c, 0xf4, 0x1b,
532 0x25, 0x24, 0x64, 0xb6, 0x24, 0x50, 0xa2, 0x4e, 0xf5, 0x98, 0x7b, 0x4b, 0xd6, 0x5e,
533 0x0d, 0x25, 0x23, 0x43, 0xab, 0xa8, 0xef, 0x77, 0x93, 0x34, 0x79, 0xde, 0xa8, 0xdd,
534 0xe2, 0x9e, 0xec, 0x56, 0xcc, 0x6a, 0xc0, 0x69,
535 ]);
536 assert_same_address(address, public_key)
537 }
538
539 #[test]
540 fn test_vector_10() {
541 let address = "DdzFFzCqrhsqTG4t3uq5UBqFrxhxGVM6bvF4q1QcZXqUpizFddEEip7dx5rbife2s9o2fRU3hVKhRp4higog7As8z42s4AMw6Pcu8vL4".parse().unwrap();
542 let public_key = XPub::from_bytes([
543 0x97, 0xb8, 0x6c, 0x69, 0xd1, 0x2a, 0xf1, 0x64, 0xdc, 0x87, 0xf2, 0x71, 0x26, 0x8f,
544 0x33, 0xbc, 0x4d, 0xee, 0xb0, 0xdf, 0xd3, 0x73, 0xc3, 0xfd, 0x3b, 0xac, 0xd4, 0x47,
545 0x53, 0xa3, 0x1d, 0xe7, 0x8f, 0x10, 0xe5, 0x55, 0x03, 0x7c, 0xd4, 0x00, 0x43, 0x6c,
546 0xcf, 0xd5, 0x38, 0x0d, 0xbb, 0xcd, 0x4d, 0x7c, 0x28, 0x0a, 0xef, 0x9e, 0xc7, 0x57,
547 0x4a, 0xe0, 0xac, 0xac, 0x0c, 0xf7, 0x9e, 0x89,
548 ]);
549 assert_same_address(address, public_key)
550 }
551}