wagyu_hdk/
address.rs

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/// Represents a Bitcoin address
18#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct HdkAddress<N: HdkNetwork> {
20    /// The Bitcoin address
21    address: String,
22    /// The format of the address
23    format: HdkFormat,
24    /// PhantomData
25    _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    /// Returns the address corresponding to the given Bitcoin private key.
34    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    /// Returns the address corresponding to the given Bitcoin public key.
45    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    /// Returns a P2PKH address from a given Bitcoin public key.
57    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    // Returns a P2WSH address in Bech32 format from a given Bitcoin script
78    pub fn p2wsh(original_script: &Vec<u8>) -> Result<Self, AddressError> {
79        let script = Sha256::digest(&original_script).to_vec();
80
81        // Organize as a hash
82        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        // Get the SHA256 hash of the script
87        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    /// Returns a P2SH_P2WPKH address from a given Bitcoin public key.
99    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    /// Returns a Bech32 address from a given Bitcoin public key.
115    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    /// Returns the format of the Bitcoin address.
132    pub fn format(&self) -> HdkFormat {
133        self.format.clone()
134    }
135
136    /// Returns a redeem script for a given Bitcoin public key.
137    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                // Check that the witness program is valid.
178                let _ = WitnessProgram::new(data.as_slice())?;
179                // Check that the address prefix corresponds to the correct network.
180                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        // Check that the address prefix corresponds to the correct network.
196        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            // Mismatched keypair
371
372            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            // Invalid address length
384
385            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            // Mismatched keypair
587
588            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            // Invalid address length
600
601            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", // invalid checksum
710            "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", // invalid witness version
711            "bc1rw5uspcuh",                               // invalid program length
712            "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", // invalid program length
713            "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",       //Invalid program length for witness version 0 (per BIP141)
714            "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",      // invalid padding
715            "bc1gmk9yu",                                  // empty data section
716        ];
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", // invalid hrp
788            "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", // Mixed case
789            "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}