1use crate::format::HdkFormat;
2use crate::network::HdkNetwork;
3use crate::private_key::HdkPrivateKey;
4use crate::public_key::HdkPublicKey;
5use crate::witness_program::WitnessProgram;
6use wagyu_model::{
7 crypto::{checksum, hash160},
8 Address, AddressError, PrivateKey,
9};
10use wagyu_model::no_std::*;
11
12use base58::{FromBase58, ToBase58};
13use bech32::{u5, Bech32, FromBase32, ToBase32};
14use core::{convert::TryFrom, fmt, marker::PhantomData, str::FromStr};
15use sha2::{Digest, Sha256};
16
17#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct HdkAddress<N: HdkNetwork> {
20 address: String,
22 format: HdkFormat,
24 _network: PhantomData<N>,
26}
27
28impl<N: HdkNetwork> Address for HdkAddress<N> {
29 type Format = HdkFormat;
30 type PrivateKey = HdkPrivateKey<N>;
31 type PublicKey = HdkPublicKey<N>;
32
33 fn from_private_key(private_key: &Self::PrivateKey, format: &Self::Format) -> Result<Self, AddressError> {
35 let public_key = private_key.to_public_key();
36 match format {
37 HdkFormat::P2PKH => Self::p2pkh(&public_key),
38 HdkFormat::P2WSH => return Err(AddressError::IncompatibleFormats(String::from("non-script"), String::from("p2wsh address"))),
39 HdkFormat::P2SH_P2WPKH => Self::p2sh_p2wpkh(&public_key),
40 HdkFormat::Bech32 => Self::bech32(&public_key),
41 }
42 }
43
44 fn from_public_key(public_key: &Self::PublicKey, format: &Self::Format) -> Result<Self, AddressError> {
46 match format {
47 HdkFormat::P2PKH => Self::p2pkh(public_key),
48 HdkFormat::P2WSH => return Err(AddressError::IncompatibleFormats(String::from("non-script"), String::from("p2wsh address"))),
49 HdkFormat::P2SH_P2WPKH => Self::p2sh_p2wpkh(public_key),
50 HdkFormat::Bech32 => Self::bech32(public_key),
51 }
52 }
53}
54
55impl<N: HdkNetwork> HdkAddress<N> {
56 pub fn p2pkh(public_key: &<Self as Address>::PublicKey) -> Result<Self, AddressError> {
58 let public_key = match public_key.is_compressed() {
59 true => public_key.to_secp256k1_public_key().serialize_compressed().to_vec(),
60 false => public_key.to_secp256k1_public_key().serialize().to_vec(),
61 };
62
63 let mut address = [0u8; 25];
64 address[0] = N::to_address_prefix(&HdkFormat::P2PKH)[0];
65 address[1..21].copy_from_slice(&hash160(&public_key));
66
67 let sum = &checksum(&address[0..21])[0..4];
68 address[21..25].copy_from_slice(sum);
69
70 Ok(Self {
71 address: address.to_base58(),
72 format: HdkFormat::P2PKH,
73 _network: PhantomData,
74 })
75 }
76
77 pub fn p2wsh(original_script: &Vec<u8>) -> Result<Self, AddressError> {
79 let script = Sha256::digest(&original_script).to_vec();
80
81 let v = N::to_address_prefix(&HdkFormat::P2WSH)[0];
83 let version = u5::try_from_u8(v)?;
84
85 let mut data = vec![version];
86 data.extend_from_slice(&script.to_vec().to_base32());
88
89 let bech32 = Bech32::new(String::from_utf8(N::to_address_prefix(&HdkFormat::Bech32))?, data)?;
90
91 Ok(Self {
92 address: bech32.to_string(),
93 format: HdkFormat::P2WSH,
94 _network: PhantomData,
95 })
96 }
97
98 pub fn p2sh_p2wpkh(public_key: &<Self as Address>::PublicKey) -> Result<Self, AddressError> {
100 let mut address = [0u8; 25];
101 address[0] = N::to_address_prefix(&HdkFormat::P2SH_P2WPKH)[0];
102 address[1..21].copy_from_slice(&hash160(&Self::create_redeem_script(public_key)));
103
104 let sum = &checksum(&address[0..21])[0..4];
105 address[21..25].copy_from_slice(sum);
106
107 Ok(Self {
108 address: address.to_base58(),
109 format: HdkFormat::P2SH_P2WPKH,
110 _network: PhantomData,
111 })
112 }
113
114 pub fn bech32(public_key: &<Self as Address>::PublicKey) -> Result<Self, AddressError> {
116 let redeem_script = Self::create_redeem_script(public_key);
117 let version = u5::try_from_u8(redeem_script[0])?;
118
119 let mut data = vec![version];
120 data.extend_from_slice(&redeem_script[2..].to_vec().to_base32());
121
122 let bech32 = Bech32::new(String::from_utf8(N::to_address_prefix(&HdkFormat::Bech32))?, data)?;
123
124 Ok(Self {
125 address: bech32.to_string(),
126 format: HdkFormat::Bech32,
127 _network: PhantomData,
128 })
129 }
130
131 pub fn format(&self) -> HdkFormat {
133 self.format.clone()
134 }
135
136 fn create_redeem_script(public_key: &<Self as Address>::PublicKey) -> [u8; 22] {
138 let mut redeem = [0u8; 22];
139 redeem[1] = 0x14;
140 redeem[2..].copy_from_slice(&hash160(&public_key.to_secp256k1_public_key().serialize_compressed()));
141 redeem
142 }
143}
144
145impl<'a, N: HdkNetwork> TryFrom<&'a str> for HdkAddress<N> {
146 type Error = AddressError;
147
148 fn try_from(address: &'a str) -> Result<Self, Self::Error> {
149 Self::from_str(address)
150 }
151}
152
153impl<N: HdkNetwork> FromStr for HdkAddress<N> {
154 type Err = AddressError;
155
156 fn from_str(address: &str) -> Result<Self, Self::Err> {
157 if address.len() < 14 || address.len() > 74 {
158 return Err(AddressError::InvalidCharacterLength(address.len()));
159 }
160
161 let prefix = &address.to_lowercase()[0..2];
162
163 if let Ok(format) = HdkFormat::from_address_prefix(prefix.as_bytes()) {
164 if HdkFormat::Bech32 == format {
165 let bech32 = Bech32::from_str(&address)?;
166 if bech32.data().is_empty() {
167 return Err(AddressError::InvalidAddress(address.to_owned()));
168 }
169
170 let data = bech32.data();
171 let version = data[0].to_u8();
172 let mut program = Vec::from_base32(&data[1..])?;
173
174 let mut data = vec![version, program.len() as u8];
175 data.append(&mut program);
176
177 let _ = WitnessProgram::new(data.as_slice())?;
179 let _ = N::from_address_prefix(prefix.as_bytes())?;
181
182 return Ok(Self {
183 address: address.to_owned(),
184 format: HdkFormat::Bech32,
185 _network: PhantomData,
186 });
187 }
188 }
189
190 let data = address.from_base58()?;
191 if data.len() != 25 {
192 return Err(AddressError::InvalidByteLength(data.len()));
193 }
194
195 let _ = N::from_address_prefix(&data[0..2])?;
197 let format = HdkFormat::from_address_prefix(&data[0..2])?;
198
199 Ok(Self {
200 address: address.into(),
201 format,
202 _network: PhantomData,
203 })
204 }
205}
206
207impl<N: HdkNetwork> fmt::Display for HdkAddress<N> {
208 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209 write!(f, "{}", self.address)
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use crate::network::*;
217 use wagyu_model::public_key::PublicKey;
218
219 fn test_from_private_key<N: HdkNetwork>(
220 expected_address: &str,
221 private_key: &HdkPrivateKey<N>,
222 format: &HdkFormat,
223 ) {
224 let address = HdkAddress::from_private_key(private_key, format).unwrap();
225 assert_eq!(expected_address, address.to_string());
226 }
227
228 fn test_from_public_key<N: HdkNetwork>(
229 expected_address: &str,
230 public_key: &HdkPublicKey<N>,
231 format: &HdkFormat,
232 ) {
233 let address = HdkAddress::from_public_key(public_key, format).unwrap();
234 assert_eq!(expected_address, address.to_string());
235 }
236
237 fn test_from_str<N: HdkNetwork>(expected_address: &str, expected_format: &HdkFormat) {
238 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
239 assert_eq!(expected_address, address.to_string());
240 assert_eq!(*expected_format, address.format);
241 }
242
243 fn test_to_str<N: HdkNetwork>(expected_address: &str, address: &HdkAddress<N>) {
244 assert_eq!(expected_address, address.to_string());
245 }
246
247 mod p2pkh_mainnet_compressed {
248 use super::*;
249
250 type N = Mainnet;
251
252 const KEYPAIRS: [(&str, &str); 5] = [
253 (
254 "L2o7RUmise9WoxNzmnVZeK83Mmt5Nn1NBpeftbthG5nsLWCzSKVg",
255 "1GUwicFwsZbdE3XyJYjmPryiiuTiK7mZgS",
256 ),
257 (
258 "KzjKw25tuQoiDyQjUG38ZRNBdnfr5eMBnTsU4JahrVDwFCpRZP1J",
259 "1J2shZV5b53GRVmTqmr3tJhkVbBML29C1z",
260 ),
261 (
262 "L2N8YRtxNMAVFAtxBt9PFSADtdvbmzFFHLSU61CtLdhYhrCGPfWh",
263 "13TdfCiGPagApSJZu1o1Y3mpfqpp6oK2GB",
264 ),
265 (
266 "KwXH1Mu4FBtGN9nRn2VkBpienaVGZKvCAkZAdE96kK71dHR1oDRs",
267 "1HaeDGHf3A2Uxeh3sKjVLYTn1hnEyuzLjF",
268 ),
269 (
270 "KwN7qiBnU4GNhboBhuPaPaFingTDKU4r27pGggwQYz865TvBT74V",
271 "12WMrNLRosydPNNYM96dwk9jDv8rDRom3J",
272 ),
273 ];
274
275 #[test]
276 fn from_private_key() {
277 KEYPAIRS.iter().for_each(|(private_key, address)| {
278 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
279 test_from_private_key(address, &private_key, &HdkFormat::P2PKH);
280 });
281 }
282
283 #[test]
284 fn from_public_key() {
285 KEYPAIRS.iter().for_each(|(private_key, address)| {
286 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
287 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
288 test_from_public_key(address, &public_key, &HdkFormat::P2PKH);
289 });
290 }
291
292 #[test]
293 fn from_str() {
294 KEYPAIRS.iter().for_each(|(_, address)| {
295 test_from_str::<N>(address, &HdkFormat::P2PKH);
296 });
297 }
298
299 #[test]
300 fn to_str() {
301 KEYPAIRS.iter().for_each(|(_, expected_address)| {
302 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
303 test_to_str(expected_address, &address);
304 });
305 }
306 }
307
308 mod p2pkh_mainnet_uncompressed {
309 use super::*;
310
311 type N = Mainnet;
312
313 const KEYPAIRS: [(&str, &str); 5] = [
314 (
315 "5K9VY2kaJ264Pj4ygobGLk7JJMgZ2i6wQ9FFKEBxoFtKeAXPHYm",
316 "18Bap2Lh5HJckiZcg8SYXoF5iPxkUoCN8u",
317 ),
318 (
319 "5KiudZRwr9wH5auJaW66WK3CGR1UzL7ZXiicvZEEaFScbbEt9Qs",
320 "192JSK8wNP867JGxHNHay3obNSXqEyyhtx",
321 ),
322 (
323 "5KCxYELatMGyVZfZFcSAw1Hz4ngiURKS22x7ydNRxcXfUzhgWMH",
324 "1NoZQSmjYHUZMbqLerwmT4xfe8A6mAo8TT",
325 ),
326 (
327 "5KT9CMP2Kgh2Afi8GbmFAHJXsH5DhcpH9KY3aH4Hkv5W6dASy7F",
328 "1NyGFd49x4nqoau8RJvjf9tGZkoUNjwd5a",
329 ),
330 (
331 "5J4cXobHh2cF2MHpLvTFjEHZCtrNHzyDzKGE8LuST2VWP129pAE",
332 "17nsg1F155BR6ie2miiLrSnMhF8GWcGq6V",
333 ),
334 ];
335
336 #[test]
337 fn from_private_key() {
338 KEYPAIRS.iter().for_each(|(private_key, address)| {
339 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
340 test_from_private_key(address, &private_key, &HdkFormat::P2PKH);
341 });
342 }
343
344 #[test]
345 fn from_public_key() {
346 KEYPAIRS.iter().for_each(|(private_key, address)| {
347 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
348 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
349 test_from_public_key(address, &public_key, &HdkFormat::P2PKH);
350 });
351 }
352
353 #[test]
354 fn from_str() {
355 KEYPAIRS.iter().for_each(|(_, address)| {
356 test_from_str::<N>(address, &HdkFormat::P2PKH);
357 });
358 }
359
360 #[test]
361 fn to_str() {
362 KEYPAIRS.iter().for_each(|(_, expected_address)| {
363 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
364 test_to_str(expected_address, &address);
365 });
366 }
367
368 #[test]
369 fn test_invalid() {
370 let private_key = "5K9VY2kaJ264Pj4ygobGLk7JJMgZ2i6wQ9FFKEBxoFtKeAXPHYm";
373 let expected_address = "12WMrNLRosydPNNYM96dwk9jDv8rDRom3J";
374
375 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
376 let address = HdkAddress::<N>::from_private_key(&private_key, &HdkFormat::P2PKH).unwrap();
377 assert_ne!(expected_address, address.to_string());
378
379 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
380 let address = HdkAddress::<N>::from_public_key(&public_key, &HdkFormat::P2PKH).unwrap();
381 assert_ne!(expected_address, address.to_string());
382
383 let address = "1";
386 assert!(HdkAddress::<N>::from_str(address).is_err());
387
388 let address = "12WMrNLRosydPNN";
389 assert!(HdkAddress::<N>::from_str(address).is_err());
390
391 let address = "12WMrNLRosydPNNYM96dwk9jDv8rDRom3";
392 assert!(HdkAddress::<N>::from_str(address).is_err());
393
394 let address = "12WMrNLRosydPNNYM96dwk9jDv8rDRom3J12WMrNLRosydPNNYM";
395 assert!(HdkAddress::<N>::from_str(address).is_err());
396
397 let address = "12WMrNLRosydPNNYM96dwk9jDv8rDRom3J12WMrNLRosydPNNYM96dwk9jDv8rDRom3J";
398 assert!(HdkAddress::<N>::from_str(address).is_err());
399 }
400 }
401
402 mod p2pkh_testnet_compressed {
403 use super::*;
404
405 type N = Testnet;
406
407 const KEYPAIRS: [(&str, &str); 5] = [
408 (
409 "cSCkpm1oSHTUtX5CHdQ4FzTv9qxLQWKx2SXMg22hbGSTNVcsUcCX",
410 "mwCDgjeRgGpfTMY1waYAJF2dGz4Q5XAx6w",
411 ),
412 (
413 "cNp5uMWdh68Nk3pwShjxsSwhGPoCYgFvE1ANuPsk6qhcT4Jvp57n",
414 "myH91eNrQKuuM7TeQYYddzL4URn6HiYbxW",
415 ),
416 (
417 "cN9aUHNMMLT9yqBJ3S5qnEPtP11nhT7ivkFK1FqNYQMozZPgMTjJ",
418 "mho8tsQtF7fx2bPKudMcXvGpUVYRHHiH4m",
419 ),
420 (
421 "cSRpda6Bhog5SUyot96HSwSzn7FZNWzudKzoCzkgZrf9hUaL3Ass",
422 "n3DgWHuAkg7eiPGH5gP8jeg3SbHBhuPJWS",
423 ),
424 (
425 "cTqLNf3iCaW61ofgmyf4ZxChUL8DZoCEPmNTCKRsexLSdNuGWQT1",
426 "mjhMXrTdq4X1dcqTaNDjwGdVaJEGBKpCRj",
427 ),
428 ];
429
430 #[test]
431 fn from_private_key() {
432 KEYPAIRS.iter().for_each(|(private_key, address)| {
433 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
434 test_from_private_key(address, &private_key, &HdkFormat::P2PKH);
435 });
436 }
437
438 #[test]
439 fn from_public_key() {
440 KEYPAIRS.iter().for_each(|(private_key, address)| {
441 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
442 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
443 test_from_public_key(address, &public_key, &HdkFormat::P2PKH);
444 });
445 }
446
447 #[test]
448 fn from_str() {
449 KEYPAIRS.iter().for_each(|(_, address)| {
450 test_from_str::<N>(address, &HdkFormat::P2PKH);
451 });
452 }
453
454 #[test]
455 fn to_str() {
456 KEYPAIRS.iter().for_each(|(_, expected_address)| {
457 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
458 test_to_str(expected_address, &address);
459 });
460 }
461 }
462
463 mod p2pkh_testnet_uncompressed {
464 use super::*;
465
466 type N = Testnet;
467
468 const KEYPAIRS: [(&str, &str); 5] = [
469 (
470 "934pVYUzZ7Sm4ZSP7MtXaQXAcMhZHpFHFBvzfW3epFgk5cWeYih",
471 "my55YLK4BmM8AyUW5px2HSSKL4yzUE5Pho",
472 ),
473 (
474 "91dTfyLPPneZA6RsAXqNuT6qTQdAuuGVCUjmBtzgd1Tnd4RQT5K",
475 "mw4afqNgGjn34okVmv9qH2WkvhfyTyNbde",
476 ),
477 (
478 "92GweXA6j4RCF3zHXGGy2ShJq6T7u9rrjmuYd9ktLHgNrWznzUC",
479 "moYi3FQZKtcc66edT3uMwVQCcswenpNscU",
480 ),
481 (
482 "92QAQdzrEDkMExM9hHV5faWqKTdXcTgXguRBcyAyYqFCjVzhDLE",
483 "mpRYQJ64ofurTCA3KKkaCjjUNqjYkUvB4w",
484 ),
485 (
486 "92H9Kf4ikaqNAJLc5tbwvbmiBWJzNDGtYmnvrigZeDVD3aqJ85Q",
487 "mvqRXtgQKqumMosPY3dLvhdYsQJV2AswkA",
488 ),
489 ];
490
491 #[test]
492 fn from_private_key() {
493 KEYPAIRS.iter().for_each(|(private_key, address)| {
494 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
495 test_from_private_key(address, &private_key, &HdkFormat::P2PKH);
496 });
497 }
498
499 #[test]
500 fn from_public_key() {
501 KEYPAIRS.iter().for_each(|(private_key, address)| {
502 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
503 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
504 test_from_public_key(address, &public_key, &HdkFormat::P2PKH);
505 });
506 }
507
508 #[test]
509 fn from_str() {
510 KEYPAIRS.iter().for_each(|(_, address)| {
511 test_from_str::<N>(address, &HdkFormat::P2PKH);
512 });
513 }
514
515 #[test]
516 fn to_str() {
517 KEYPAIRS.iter().for_each(|(_, expected_address)| {
518 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
519 test_to_str(expected_address, &address);
520 });
521 }
522 }
523
524 mod p2sh_p2wpkh_mainnet {
525 use super::*;
526
527 type N = Mainnet;
528
529 const KEYPAIRS: [(&str, &str); 5] = [
530 (
531 "L3YPi4msjWdkqiH3ojfg3nwDmNYBrDScAtcugYBJSgsc3HTcqqjP",
532 "38EMCierP738rgYVHjj1qJANHKgx1166TN",
533 ),
534 (
535 "KxxFoGgBdqqyGznT6he2wKYcFKm5urSANec7qjLeu3caEadSo5pv",
536 "3Kc9Vqzi4eUn42g1KWewVPvtTpWpUwjNFv",
537 ),
538 (
539 "KziUnVFNBniwmvei7JvNJNcQZ27TDZe5VNn7ieRNK7QgMEVfKdo9",
540 "3C2niRgmFP2kz47AAWASqq5nWobDke1AfJ",
541 ),
542 (
543 "Kx5veRe18jnV1rZiJA7Xerh5qLpwnbjV38r83sKcF1W9d1K2TGSp",
544 "3Pai7Ly86pddxxwZ7rUhXjRJwog4oKqNYK",
545 ),
546 (
547 "L4RrcBy6hZMw3xD4eAFXDTWPhasd9N3rYrYgfiR9pnGuLdv7UsWZ",
548 "3LW5tQGWBCiRLfCgk1FEUpwKoymFF8Lk7P",
549 ),
550 ];
551
552 #[test]
553 fn from_private_key() {
554 KEYPAIRS.iter().for_each(|(private_key, address)| {
555 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
556 test_from_private_key(address, &private_key, &HdkFormat::P2SH_P2WPKH);
557 });
558 }
559
560 #[test]
561 fn from_public_key() {
562 KEYPAIRS.iter().for_each(|(private_key, address)| {
563 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
564 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
565 test_from_public_key(address, &public_key, &HdkFormat::P2SH_P2WPKH);
566 });
567 }
568
569 #[test]
570 fn from_str() {
571 KEYPAIRS.iter().for_each(|(_, address)| {
572 test_from_str::<N>(address, &HdkFormat::P2SH_P2WPKH);
573 });
574 }
575
576 #[test]
577 fn to_str() {
578 KEYPAIRS.iter().for_each(|(_, expected_address)| {
579 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
580 test_to_str(expected_address, &address);
581 });
582 }
583
584 #[test]
585 fn test_invalid() {
586 let private_key = "L3YPi4msjWdkqiH3ojfg3nwDmNYBrDScAtcugYBJSgsc3HTcqqjP";
589 let expected_address = "3Pai7Ly86pddxxwZ7rUhXjRJwog4oKqNYK";
590
591 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
592 let address = HdkAddress::<N>::from_private_key(&private_key, &HdkFormat::P2SH_P2WPKH).unwrap();
593 assert_ne!(expected_address, address.to_string());
594
595 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
596 let address = HdkAddress::<N>::from_public_key(&public_key, &HdkFormat::P2SH_P2WPKH).unwrap();
597 assert_ne!(expected_address, address.to_string());
598
599 let address = "3";
602 assert!(HdkAddress::<N>::from_str(address).is_err());
603
604 let address = "3Pai7Ly86pddxxwZ7";
605 assert!(HdkAddress::<N>::from_str(address).is_err());
606
607 let address = "3Pai7Ly86pddxxwZ7rUhXjRJwog4oKqNY";
608 assert!(HdkAddress::<N>::from_str(address).is_err());
609
610 let address = "3Pai7Ly86pddxxwZ7rUhXjRJwog4oKqNYK3Pai7Ly86pddxxwZ7";
611 assert!(HdkAddress::<N>::from_str(address).is_err());
612
613 let address = "3Pai7Ly86pddxxwZ7rUhXjRJwog4oKqNYK3Pai7Ly86pddxxwZ7rUhXjRJwog4oKqNYK";
614 assert!(HdkAddress::<N>::from_str(address).is_err());
615 }
616 }
617
618 mod p2sh_p2wpkh_testnet {
619 use super::*;
620
621 type N = Testnet;
622
623 const KEYPAIRS: [(&str, &str); 5] = [
624 (
625 "cSoLwgnCNXck57BGxdGRV4SQ42EUExV6ykdMK1RKwcEaB9MDZWki",
626 "2N9e892o8DNZs25xHBwRPZLsrZK3dBsrH3d",
627 ),
628 (
629 "cQEUStvLToCNEQ6QGPyTmGFCTiMWWzQDkkj2tUPEiAzafybgUyu4",
630 "2MwX52EZPfK1sq12H3ikgTybrUvKG62b9rV",
631 ),
632 (
633 "cRv6jkNhTNEL7563ezNuwWP9W7gEcjh19YbmHtTbrDUQsXF5PjoG",
634 "2N2XaYpYxX6C6attRQ1NXJUgZdm861CPHJ7",
635 ),
636 (
637 "cNyZJwad53Y38RthGrmYyoHAtsT7cPisjW92HJ4RcAP1mC6xBpSm",
638 "2N3HzUQ4DzfEbxYp3XtpEKBBSdBS1uc2DLk",
639 ),
640 (
641 "cUqEZZwzvdWv6pmnWV5eb68hNeWt3jDZgtCGf66rqk3bnbsXArVE",
642 "2N5isk4qJHAKfLV987ePAqjLobJkrWVCuhj",
643 ),
644 ];
645
646 #[test]
647 fn from_private_key() {
648 KEYPAIRS.iter().for_each(|(private_key, address)| {
649 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
650 test_from_private_key(address, &private_key, &HdkFormat::P2SH_P2WPKH);
651 });
652 }
653
654 #[test]
655 fn from_public_key() {
656 KEYPAIRS.iter().for_each(|(private_key, address)| {
657 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
658 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
659 test_from_public_key(address, &public_key, &HdkFormat::P2SH_P2WPKH);
660 });
661 }
662
663 #[test]
664 fn from_str() {
665 KEYPAIRS.iter().for_each(|(_, address)| {
666 test_from_str::<N>(address, &HdkFormat::P2SH_P2WPKH);
667 });
668 }
669
670 #[test]
671 fn to_str() {
672 KEYPAIRS.iter().for_each(|(_, expected_address)| {
673 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
674 test_to_str(expected_address, &address);
675 });
676 }
677 }
678
679 mod bech32_mainnet {
680 use super::*;
681 use crate::public_key::HdkPublicKey;
682
683 type N = Mainnet;
684
685 const KEYPAIRS: [(&str, &str); 5] = [
686 (
687 "KyQ2StwnZ644hRLXdMrRUBGKT9WJcVVhnuzz2u528VHeAr5kFimR",
688 "bc1qztqceddvavsxdgju4cz6z42tawu444m8uttmxg",
689 ),
690 (
691 "L3aeYHnEBqNt6tKTgUyweY9HvZ3mcLMsq7KQZkSu9Mj8Z1JN9oC2",
692 "bc1q0s92yg9m0zqjjc07z5lhhlu3k6ue93fgzku2wy",
693 ),
694 (
695 "L3w7zoPzip7o6oXz3zVLNHbT2UyLBWuVG7uaEZDqneRjgjw9vmCE",
696 "bc1q7rzq3xup0hdklkg6p8harn97zszuqwuaqc9l8t",
697 ),
698 (
699 "L2C75eEmRTU8yWeSwtQ6xeumoNVmCb2uEMfzuo5dkdMwpUWwYtRU",
700 "bc1qgw90ly6jkpprh6g8atk5cxnwcavh4e0p2k3h65",
701 ),
702 (
703 "L2CJfT3w1VPDDLQfJKTmSb6gtSGyE1HxWYsitaq5Y1XLXTMC5Qmx",
704 "bc1qgfzgf6pzuk7y88zk54nxluzg6dv9jett9suzuf",
705 ),
706 ];
707
708 const INVALID: [&str; 7] = [
709 "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", "bc1rw5uspcuh", "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", "bc1gmk9yu", ];
717
718 #[test]
719 fn from_invalid_address() {
720 INVALID.iter().for_each(|invalid_bech32| {
721 assert_eq!(true, HdkAddress::<N>::from_str(invalid_bech32).is_err());
722 });
723 }
724
725 #[test]
726 fn from_private_key() {
727 KEYPAIRS.iter().for_each(|(private_key, address)| {
728 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
729 test_from_private_key(address, &private_key, &HdkFormat::Bech32);
730 });
731 }
732
733 #[test]
734 fn from_public_key() {
735 KEYPAIRS.iter().for_each(|(private_key, address)| {
736 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
737 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
738 test_from_public_key(address, &public_key, &HdkFormat::Bech32);
739 });
740 }
741
742 #[test]
743 fn from_str() {
744 KEYPAIRS.iter().for_each(|(_, address)| {
745 test_from_str::<N>(address, &HdkFormat::Bech32);
746 });
747 }
748
749 #[test]
750 fn to_str() {
751 KEYPAIRS.iter().for_each(|(_, expected_address)| {
752 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
753 test_to_str(expected_address, &address);
754 });
755 }
756 }
757
758 mod bech32_testnet {
759 use super::*;
760
761 type N = Testnet;
762
763 const KEYPAIRS: [(&str, &str); 5] = [
764 (
765 "cVQmTtLoCjDJAXVj778xyww1ZbpJQt7Vq9sDt8Mdmw97Rg7TaNes",
766 "tb1qmkvfprg8pkr3apv9gyykmhe26fexyla076ss0g",
767 ),
768 (
769 "cTxHRG8MgrnSQstuMs5VnQcFBjrs67NmiJGo1kevnJDS7QFGLUAi",
770 "tb1qfe0dnfpxp4c9lfdjzvmf5q72jg83emgknmcxxd",
771 ),
772 (
773 "cSN1N2Vmhg9jPSUpXyQj8WbNUgeLHbC3Yj8SFX2N834YMepMwNZH",
774 "tb1qx4jm2s3ks5vadh2ja3flsn4ckjzhdxmxmmrrzx",
775 ),
776 (
777 "cMvmoqYYzr4dgzNZ22PvaqSnNx98evXc1b7m8FfK9SdCqhiWdP2c",
778 "tb1ql0g42pusevlgd0jh9gyr32s0h0pe96wpnrqg3m",
779 ),
780 (
781 "cVodD5ifcBjYVUs19GLwz6YzU2hUhdNagBx9QQcZp7TgjLuuFYn3",
782 "tb1qwnh7hu5qfrjsk9pyn3vvmzr48v4l8kp4ug0txn",
783 ),
784 ];
785
786 const INVALID: [&str; 3] = [
787 "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
790 ];
791
792 #[test]
793 fn from_invalid_address() {
794 INVALID.iter().for_each(|invalid_bech32| {
795 assert_eq!(true, HdkAddress::<N>::from_str(invalid_bech32).is_err());
796 });
797 }
798
799 #[test]
800 fn from_private_key() {
801 KEYPAIRS.iter().for_each(|(private_key, address)| {
802 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
803 test_from_private_key(address, &private_key, &HdkFormat::Bech32);
804 });
805 }
806
807 #[test]
808 fn from_public_key() {
809 KEYPAIRS.iter().for_each(|(private_key, address)| {
810 let private_key = HdkPrivateKey::<N>::from_str(private_key).unwrap();
811 let public_key = HdkPublicKey::<N>::from_private_key(&private_key);
812 test_from_public_key(address, &public_key, &HdkFormat::Bech32);
813 });
814 }
815
816 #[test]
817 fn from_str() {
818 KEYPAIRS.iter().for_each(|(_, address)| {
819 test_from_str::<N>(address, &HdkFormat::Bech32);
820 });
821 }
822
823 #[test]
824 fn to_str() {
825 KEYPAIRS.iter().for_each(|(_, expected_address)| {
826 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
827 test_to_str(expected_address, &address);
828 });
829 }
830 }
831
832 mod p2wsh_testnet {
833 use super::*;
834
835 type N = Testnet;
836
837 const SCRIPTPAIRS: [(&str, &str); 2] = [
838 (
839 "210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
840 "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
841 ),
842 (
843 "210253be79afe84fd9342c1f52024379b6da6299ea98844aee23838e8e678a765f7cac",
844 "tb1qhmdep02f0jpjxs36ckyzjtfesknu8a8xmhnva7f3vw95t9g6q4ksaqhl9x"
845 )
846 ];
847
848 #[test]
849 fn from_str() {
850 SCRIPTPAIRS.iter().for_each(|(script, address)| {
851 let script_hex= hex::decode(script).unwrap();
852 let new_address = HdkAddress::<N>::p2wsh(&script_hex).unwrap();
853 assert_eq!(new_address.to_string(), address.to_string());
854 assert_eq!(new_address.format, HdkFormat::P2WSH);
855 });
856 }
857
858 #[test]
859 fn to_str() {
860 SCRIPTPAIRS.iter().for_each(|(_, expected_address)| {
861 let address = HdkAddress::<N>::from_str(expected_address).unwrap();
862 test_to_str(expected_address, &address);
863 });
864 }
865 }
866
867}