anychain_bitcoin/
public_key.rs

1use crate::{BitcoinAddress, BitcoinFormat, BitcoinNetwork};
2use anychain_core::{hex, Address, AddressError, PublicKey, PublicKeyError};
3use core::{fmt, marker::PhantomData, str::FromStr};
4
5/// Represents a Bitcoin public key
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct BitcoinPublicKey<N: BitcoinNetwork> {
8    /// The ECDSA public key
9    public_key: libsecp256k1::PublicKey,
10    /// If true, the public key is serialized in compressed form
11    compressed: bool,
12    /// PhantomData
13    _network: PhantomData<N>,
14}
15
16impl<N: BitcoinNetwork> PublicKey for BitcoinPublicKey<N> {
17    type SecretKey = libsecp256k1::SecretKey;
18    type Address = BitcoinAddress<N>;
19    type Format = BitcoinFormat;
20
21    /// Returns the address corresponding to the given public key.
22    fn from_secret_key(secret_key: &Self::SecretKey) -> Self {
23        Self {
24            public_key: libsecp256k1::PublicKey::from_secret_key(secret_key),
25            compressed: true,
26            _network: PhantomData,
27        }
28    }
29
30    /// Returns the address of the corresponding private key.
31    fn to_address(&self, format: &Self::Format) -> Result<Self::Address, AddressError> {
32        Self::Address::from_public_key(self, format)
33    }
34}
35
36impl<N: BitcoinNetwork> BitcoinPublicKey<N> {
37    /// Returns a public key given a secp256k1 public key.
38    pub fn from_secp256k1_public_key(
39        public_key: libsecp256k1::PublicKey,
40        compressed: bool,
41    ) -> Self {
42        Self {
43            public_key,
44            compressed,
45            _network: PhantomData,
46        }
47    }
48
49    /// Returns the secp256k1 public key of the public key.
50    pub fn to_secp256k1_public_key(&self) -> libsecp256k1::PublicKey {
51        self.public_key
52    }
53
54    /// Serialize the Bitcoin public key as a vector of u8
55    pub fn serialize(&self) -> Vec<u8> {
56        match self.compressed {
57            true => self.public_key.serialize_compressed().to_vec(),
58            false => self.public_key.serialize().to_vec(),
59        }
60    }
61
62    /// Returns `true` if the public key is in compressed form.
63    pub fn is_compressed(&self) -> bool {
64        self.compressed
65    }
66}
67
68impl<N: BitcoinNetwork> FromStr for BitcoinPublicKey<N> {
69    type Err = PublicKeyError;
70
71    fn from_str(public_key: &str) -> Result<Self, Self::Err> {
72        let compressed = public_key.len() == 66;
73        let p = hex::decode(public_key)
74            .map_err(|error| PublicKeyError::Crate("hex", format!("{:?}", error)))?;
75        let public_key = libsecp256k1::PublicKey::parse_slice(&p, None)
76            .map_err(|error| PublicKeyError::Crate("libsecp256k1", format!("{:?}", error)))?;
77        Ok(Self {
78            public_key,
79            compressed,
80            _network: PhantomData,
81        })
82    }
83}
84
85impl<N: BitcoinNetwork> fmt::Display for BitcoinPublicKey<N> {
86    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        if self.compressed {
88            for s in &self.public_key.serialize_compressed()[..] {
89                write!(f, "{:02x}", s)?;
90            }
91        } else {
92            for s in &self.public_key.serialize()[..] {
93                write!(f, "{:02x}", s)?;
94            }
95        }
96        Ok(())
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::network::*;
104
105    fn test_to_address<N: BitcoinNetwork>(
106        expected_address: &BitcoinAddress<N>,
107        expected_format: &BitcoinFormat,
108        public_key: &BitcoinPublicKey<N>,
109    ) {
110        let address = public_key.to_address(expected_format).unwrap();
111        assert_eq!(*expected_address, address);
112    }
113
114    fn test_from_str<N: BitcoinNetwork>(
115        expected_public_key: &str,
116        expected_address: &str,
117        expected_compressed: bool,
118        expected_format: &BitcoinFormat,
119    ) {
120        let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
121        let address = public_key.to_address(expected_format).unwrap();
122        assert_eq!(expected_public_key, public_key.to_string());
123        assert_eq!(expected_compressed, public_key.compressed);
124        assert_eq!(expected_address, address.to_string());
125        assert_eq!(*expected_format, address.format());
126    }
127
128    fn test_to_str<N: BitcoinNetwork>(expected_public_key: &str, public_key: &BitcoinPublicKey<N>) {
129        assert_eq!(expected_public_key, public_key.to_string());
130    }
131
132    mod p2pkh_mainnet_compressed {
133        use super::*;
134
135        type N = Bitcoin;
136        const KEYPAIRS: [(&str, &str, &str); 5] = [
137            (
138                "L5hax5dZaByC3kJ4aLrZgnMXGSQReqRDYNqM1VAeXpqDRkRjX42H",
139                "039ed714bf521e96e3f3609b74da898e44d0fb64ba68c62c57852470ffc28e3db5",
140                "1uNM6oivjCJU2RcsNbfooVwcPjDRhjW7U",
141            ),
142            (
143                "L4uNhZS86VLiKKGZZGNxwP7s67EfYfQ7S9bNnVfVbU9GBVVo2xoD",
144                "03a385ac59a31841764d55e7c8a243482a89073785524f0c45335afcf425d567b1",
145                "16sz5SMFeRfwaqY6wKzkiufwPmF1J7RhAx",
146            ),
147            (
148                "KyH2BrThuUnzSXxDrDxQbpK277HxZfwPxVaCs5cwbzDEVNno2nts",
149                "028fa046ccfbb4ff134a5e0e8969d8085c6e2a1a52d793d351d4ddf02cd43d64b2",
150                "17QAwDwsLpehmCqSQXdHZb8vpsYVDnX7ic",
151            ),
152            (
153                "KxEqpgCMencSHwiCG6xix9teUrB7JQNy2c7LKU56fZKZtP46nEca",
154                "02f7fb7e7d5dc97a5e1cd36b1ea3218234649f98f32cf08f45f8cd742860f676bf",
155                "1ESGcxbb96gQmJuEQsSapdk1jH6JaEnbU9",
156            ),
157            (
158                "L2gCQPMpS5PqGvcBFMtYRT5S5jAo6WaNL1aPLvY2JkykkKSkqtm5",
159                "02aad3c8ee3dc6753a5284c97124f0047b2af0b91ba256b6262e07fcc2630f6b7f",
160                "1MRCogND3SKqa4xRZNpSC6iQxtwCpvmzfE",
161            ),
162        ];
163
164        #[test]
165        fn to_address() {
166            KEYPAIRS.iter().for_each(|(_, public_key, address)| {
167                let address = BitcoinAddress::<N>::from_str(address).unwrap();
168                let public_key = BitcoinPublicKey::<N>::from_str(public_key).unwrap();
169                test_to_address(&address, &BitcoinFormat::P2PKH, &public_key);
170            });
171        }
172
173        #[test]
174        fn from_str() {
175            KEYPAIRS
176                .iter()
177                .for_each(|(_, expected_public_key, expected_address)| {
178                    test_from_str::<N>(
179                        expected_public_key,
180                        expected_address,
181                        true,
182                        &BitcoinFormat::P2PKH,
183                    );
184                });
185        }
186
187        #[test]
188        fn to_str() {
189            KEYPAIRS.iter().for_each(|(_, expected_public_key, _)| {
190                let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
191                test_to_str(expected_public_key, &public_key);
192            });
193        }
194    }
195
196    mod p2pkh_mainnet_uncompressed {
197        use super::*;
198
199        type N = Bitcoin;
200        const KEYPAIRS: [(&str, &str, &str); 5] = [
201            (
202                "5KV26gjX4sYAkXvDnqZZuEyFUh1DKjgZ8wTKL7Fpm4ppJ8kpZQu",
203                "0489efe59c51e542f4cc7e2464ba3835d0a1a3daf351e70db57053c4712aca58796a933d1331078c364b94dd53aba2357a01f446c22efedcea8ebce2167a9e1df8",
204                "1KGHasyEpQZSHLea2GV3taTFZcw3uP7AAJ"
205            ),
206            (
207                "5JUfnMYvM4g94psa1p2MUfQptbiouXYbb5oskjY7mZ151rXDFTi",
208                "04cf0ead0ea5df0700a4f063edf40397b377147d99f8f9404606e80dd931c819d2b571ab64754d27e69de5226f316e2dcab9f8b3b706d08104bcfe06f0e6dc7ff3",
209                "1Ja8ReiHyPwNdWHZdJZVN9ZV6cNzC8DbTy"
210            ),
211            (
212                "5K2enrnWqJcQuHLeijT76YEqDagWo3cQLnPYk2CezrJ7A61QG5y",
213                "04a215f5764beef937296f6797407e51b8823eb418c3d65f48c0950ee775504c3539ca06ef419c7c70cbdf30930c25b5abb8040a89e089b786363c2bd78a07f464",
214                "1PvWPvCZV4mQACqXp3AsFvQHtyfq2eZG9c"
215            ),
216            (
217                "5JnV7DtVZvwbVeRLvXQSzyg5WxMYJMEQbJk8VoYhzDTz4tawudY",
218                "04005e271fa3305bac32c5951fb84b35303b1231817e538aa5af6b145faae409a01f9e8c0330f4901577aacd43682fe2af39e69dcfaa7cff7390c006b3b66e90ad",
219                "1FCHrsTrzxJy3sq1pQKLBQojuvYyMBzs4g"
220            ),
221            (
222                "5KVeWqioENjhaYZqXZX4nEfwEysJjXEvYfaeQx4pM2HK51ZW7Ur",
223                "04b6c8c8a6e9ad27366d8e6a0fa6c11f15ad7a8f15ac0c1d38c714df1f6b00b102773c7ebb0d718fc93808fdaf6c6b4ff6213909d50a94d5d6c8b472a9d1f30d99",
224                "1Hb6umXZs26hUZMt59nbkTAAfMpsmTkCBs"
225            )
226        ];
227
228        #[test]
229        fn to_address() {
230            KEYPAIRS.iter().for_each(|(_, public_key, address)| {
231                let address = BitcoinAddress::<N>::from_str(address).unwrap();
232                let public_key = BitcoinPublicKey::<N>::from_str(public_key).unwrap();
233                test_to_address(&address, &BitcoinFormat::P2PKH, &public_key);
234            });
235        }
236
237        #[test]
238        fn from_str() {
239            KEYPAIRS
240                .iter()
241                .for_each(|(_, expected_public_key, expected_address)| {
242                    test_from_str::<N>(
243                        expected_public_key,
244                        expected_address,
245                        false,
246                        &BitcoinFormat::P2PKH,
247                    );
248                });
249        }
250
251        #[test]
252        fn to_str() {
253            KEYPAIRS.iter().for_each(|(_, expected_public_key, _)| {
254                let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
255                test_to_str(expected_public_key, &public_key);
256            });
257        }
258    }
259
260    mod p2pkh_testnet_compressed {
261        use super::*;
262
263        type N = BitcoinTestnet;
264        const KEYPAIRS: [(&str, &str, &str); 5] = [
265            (
266                "cNB6GpygWSZNRG5hotKjdAaNfgrzx984QYb2uj9rHpaCDkyy2aAz",
267                "02bc25a326a8fa59edd1a2adff51956ea3c61f404cff6e926225b3fe3b303561ac",
268                "mkerhifaLqJgAgrAjLomUStznPgVewNkka",
269            ),
270            (
271                "cW4GQXEykwWJHVfRH8u25MzpzaU5XQDekdpdQbj9f9V7PLm25m4n",
272                "02e21263a700b22c16088dc45fb10d38cc8c4ebb4cdcb612e6551d972b60aa2446",
273                "n3NUsMjN3D6EWZ5nKZLvHnVwaAxfybQDq9",
274            ),
275            (
276                "cSA6Mo1PYYK2uaDH22KoreQZdkSLobcrxZwnLcotDiYocCSjCVXy",
277                "0355210590fbe6dcb663c6166cd5cb169169e0d4bac76ce78d4ac29ddf683b2541",
278                "mzt1DhTJMzXarvJukPUxnfA1syVhDuZapf",
279            ),
280            (
281                "cUVDoLpgXFYZGmjoyMusNEZJ174wk8ggjyH2Uo7L5nB1w5werAjX",
282                "0259b863ba239379d6ebee4074b6f9c9f7f23a581ff529aa8d1431d94cb2f3cd99",
283                "mxe1oRLS21dEqt6H77GPGUx59Zj4ucUBbc",
284            ),
285            (
286                "cRhBWs3Bg9oXERSEY8GLaZjN7eb1FmkCnRdmwjCG2pVXVPUqXNiT",
287                "02826afccd44e32a9542f72a3a7753b99dbaf4a800bb70b6155510b1ce7a4bf607",
288                "mpvYGW4UNjYRaQ1adpE8ThYNXCVkWjhAPb",
289            ),
290        ];
291
292        #[test]
293        fn to_address() {
294            KEYPAIRS.iter().for_each(|(_, public_key, address)| {
295                let address = BitcoinAddress::<N>::from_str(address).unwrap();
296                let public_key = BitcoinPublicKey::<N>::from_str(public_key).unwrap();
297                test_to_address(&address, &BitcoinFormat::P2PKH, &public_key);
298            });
299        }
300
301        #[test]
302        fn from_str() {
303            KEYPAIRS
304                .iter()
305                .for_each(|(_, expected_public_key, expected_address)| {
306                    test_from_str::<N>(
307                        expected_public_key,
308                        expected_address,
309                        true,
310                        &BitcoinFormat::P2PKH,
311                    );
312                });
313        }
314
315        #[test]
316        fn to_str() {
317            KEYPAIRS.iter().for_each(|(_, expected_public_key, _)| {
318                let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
319                test_to_str(expected_public_key, &public_key);
320            });
321        }
322    }
323
324    mod p2pkh_testnet_uncompressed {
325        use super::*;
326
327        type N = BitcoinTestnet;
328        const KEYPAIRS: [(&str, &str, &str); 5] = [
329            (
330                "93W1kMkD1kAfevtDQ3LWortt8zjKqSSqonLxPvWFqg57arcwUru",
331                "048bb370869871417660abdacebf25f786e69c6e861b1c11346071cc9ad69690c2dc19fd3965455afc9a662feef3432b88cc99e31fa30ba93993ca21322e43e894",
332                "n4jx6NanXkXu7XSZrXBMKsFccxcp35UtJv"
333            ),
334            (
335                "92FshhFbVnbtpbvpdzGmKEnNkToJnvm6L45LhDQqn1Kxjp8d4oR",
336                "04092301037dc083952053ccd320b5e12b30839fa0380d8a2c27547de4a527806962c5d1efc9e748cf6003fcc7ff0784caee9fa36d9b7ea330a613e4b71f8df0f9",
337                "n47WkmoSwebNXyvbkRdubZmFbGm5SbKh1A"
338            ),
339            (
340                "92PbnSrnyLzS2HBNy4Vh2zg9hkVrztdxxDFihz92rBDyX25xF8N",
341                "043e8f6512364e73a695f2b14b284a1c58ca9cbac2d8dd7dcf15f135260e87f1d0f89270f5a8d76b4e611861d68c955dc1524df4c20bb080bf0c0f536383379f91",
342                "n3TWdpM742F8mxkcWQw8h2cifxyy82V2ov"
343            ),
344            (
345                "92SbtaaCwUuHmzYGdi9xp5GbfUivbLHTAkqxeWaX88E1Q9HZJfs",
346                "0402acd5144558b5e779dead4c9e9b733e00b6e0554a243433bfccc730923a0beacd93f2b73c75f67d65fb830bde1cf101a8daea12ee3b659ef31fa274f52435d0",
347                "muFcYctkUkfWW55n2GMUafkw71kbZuduNv"
348            ),
349            (
350                "91sSacE166SmPMoysEfZrQmM9aHgSfZbEfjmMf6nY8qBgvQMB1i",
351                "04c8d1e7d88969b4345c874f50af41b8d310dd666c0a3df52c46c238a345fbda73165fccdedffb67390e87e81040bff8415b8d7c5a6bbc441c89841cb74012501d",
352                "mwSgCKvDt3SoBxa3RZB1kXbxzX3oMvXxvT"
353            )
354        ];
355
356        #[test]
357        fn to_address() {
358            KEYPAIRS.iter().for_each(|(_, public_key, address)| {
359                let address = BitcoinAddress::<N>::from_str(address).unwrap();
360                let public_key = BitcoinPublicKey::<N>::from_str(public_key).unwrap();
361                test_to_address(&address, &BitcoinFormat::P2PKH, &public_key);
362            });
363        }
364
365        #[test]
366        fn from_str() {
367            KEYPAIRS
368                .iter()
369                .for_each(|(_, expected_public_key, expected_address)| {
370                    test_from_str::<N>(
371                        expected_public_key,
372                        expected_address,
373                        false,
374                        &BitcoinFormat::P2PKH,
375                    );
376                });
377        }
378
379        #[test]
380        fn to_str() {
381            KEYPAIRS.iter().for_each(|(_, expected_public_key, _)| {
382                let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
383                test_to_str(expected_public_key, &public_key);
384            });
385        }
386    }
387
388    mod p2sh_p2wpkh_mainnet {
389        use super::*;
390
391        type N = Bitcoin;
392        const KEYPAIRS: [(&str, &str, &str); 5] = [
393            (
394                "KyTx39W9vjeGRRjvZna5bbFGEpuih9pG5KBnxUJN7bChpGHHZuJN",
395                "02468791fee1444df3a6e786e2f9da79198f8902387e1fa5a2c051950c4df51ab4",
396                "3QKTruktKRSmY3QfhoijwT1BU1npSGMQPG",
397            ),
398            (
399                "L4EYurAwjsXiQrZ9XWdWdf5LDVAGAwGW58LtgZhGtR1cXUjS8oWD",
400                "024a185e896e5cf4cb0b441a18b5eac1a682e1848731449a5bb4c4a55c6d0fac3f",
401                "3JU5wvE4YrpZ5CgwpALBJB1C4YJjuZjXhj",
402            ),
403            (
404                "KyMSREGeHw2fnaRhTn1Cq9HYot9QR9AyUX6z8RbRF5Zr98qdmTjJ",
405                "0337893947d9738d6d026bd5fa86d3c563ebc5840916d0ea50b143a83db7ef9de7",
406                "3NzBJJPE3gaq5T9bmLJR4iHhmSHTgJdus4",
407            ),
408            (
409                "L5DtYc8LkDBQWWUAsWcgQZZqpVfUYCLyHZveGXKGT2hCS4pnnmqp",
410                "03eb86647457f2dfda66e7574d26cc4a6ecca472bc2ff331f333eb21614a0c58ee",
411                "3JUHwBJu1Figs4FesZPCgfBQKJC4GHjwPa",
412            ),
413            (
414                "L4GoufTyWZoy1WDzRDacywokD28C7amVH9Jyfsyr8XZpR8Pog7gK",
415                "025195d4c21c7001103649f0bfb37f61a0da1e345e5847b005dbd10f0b7b7f9e6f",
416                "3L6rBuHhf3MzY1qEXMxeyY18bo8H8uKb4D",
417            ),
418        ];
419
420        #[test]
421        fn to_address() {
422            KEYPAIRS.iter().for_each(|(_, public_key, address)| {
423                let address = BitcoinAddress::<N>::from_str(address).unwrap();
424                let public_key = BitcoinPublicKey::<N>::from_str(public_key).unwrap();
425                test_to_address(&address, &BitcoinFormat::P2SH_P2WPKH, &public_key);
426            });
427        }
428
429        #[test]
430        fn from_str() {
431            KEYPAIRS
432                .iter()
433                .for_each(|(_, expected_public_key, expected_address)| {
434                    test_from_str::<N>(
435                        expected_public_key,
436                        expected_address,
437                        true,
438                        &BitcoinFormat::P2SH_P2WPKH,
439                    );
440                });
441        }
442
443        #[test]
444        fn to_str() {
445            KEYPAIRS.iter().for_each(|(_, expected_public_key, _)| {
446                let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
447                test_to_str(expected_public_key, &public_key);
448            });
449        }
450    }
451
452    mod p2sh_p2wpkh_testnet {
453        use super::*;
454
455        type N = BitcoinTestnet;
456        const KEYPAIRS: [(&str, &str, &str); 5] = [
457            (
458                "cPYtDeoeHg3wXp7hzcZ8Bu51HtN74yNdSDtdRuXamKCyzvU2oQM2",
459                "025718c5ebfbbb3566bf4757ca57822377eca9be9ace4d038052156dfe73f4c439",
460                "2Mt46mJZ8i7x2eiN77MekrD4UJg6GFt9mUh",
461            ),
462            (
463                "cMyPKTkYyhZS9cvrxkJZKFLEtqML6suBuDyZfFKXqGeHvnEPaD3x",
464                "0236cd9b36cc3e08bf457ff6663b66d049ad942253d52bd5d939ea654d872bd5f3",
465                "2MvRwrFLhxfwP96t6z6Th28No4Va19fogj3",
466            ),
467            (
468                "cTWWzheif86K9fouCo5gg1G4pEdGbLRrnHbY3uRr6AmhjKwNUrGh",
469                "021779b92c6a29c0bb554af8a059d51e08c900ca652fac13c1dab62da34016b722",
470                "2N1STUKnC6atTS2JttzdbP1891sCrD5i6xu",
471            ),
472            (
473                "cV2L63nMM3WZwrU9EKFFP218XAQBhsDmEQ9uTw3vhMAz25Gna9nF",
474                "032a1af62e21831cc0951daf4f2e8f457bc59a4dc716e86f066b4de40020c9c8f1",
475                "2N8mGnLgSL8GUyDELStD4YVGawdai52ax9q",
476            ),
477            (
478                "cTB6EeZgiGCziMQycbUCbn25AkipGACtY1Lyd1rAhGnTPEwHSHQT",
479                "027ebe9c4c3d976c490d34aad11d66558b052e6359925f8b33e51428dfdf59ad79",
480                "2N2JVpNUWsnV4MZMF11ewG2BVjhHoVNkv6K",
481            ),
482        ];
483
484        #[test]
485        fn to_address() {
486            KEYPAIRS.iter().for_each(|(_, public_key, address)| {
487                let address = BitcoinAddress::<N>::from_str(address).unwrap();
488                let public_key = BitcoinPublicKey::<N>::from_str(public_key).unwrap();
489                test_to_address(&address, &BitcoinFormat::P2SH_P2WPKH, &public_key);
490            });
491        }
492
493        #[test]
494        fn from_str() {
495            KEYPAIRS
496                .iter()
497                .for_each(|(_, expected_public_key, expected_address)| {
498                    test_from_str::<N>(
499                        expected_public_key,
500                        expected_address,
501                        true,
502                        &BitcoinFormat::P2SH_P2WPKH,
503                    );
504                });
505        }
506
507        #[test]
508        fn to_str() {
509            KEYPAIRS.iter().for_each(|(_, expected_public_key, _)| {
510                let public_key = BitcoinPublicKey::<N>::from_str(expected_public_key).unwrap();
511                test_to_str(expected_public_key, &public_key);
512            });
513        }
514    }
515
516    #[test]
517    fn test_p2pkh_invalid() {
518        type N = Bitcoin;
519
520        // Invalid public key length
521
522        let public_key = "0";
523        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
524
525        let public_key = "039ed714bf521e96e3f3609b74da898e44";
526        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
527
528        let public_key = "039ed714bf521e96e3f3609b74da898e44d0fb64ba68c62c57852470ffc28e3db";
529        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
530
531        let public_key =
532            "039ed714bf521e96e3f3609b74da898e44d0fb64ba68c62c57852470ffc28e3db5039ed714bf521e96e3f3609b74da898e44";
533        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
534
535        let public_key = "039ed714bf521e96e3f3609b74da898e44d0fb64ba68c62c57852470ffc28e3db5039ed714bf521e96e3f3609b74da898e44d0fb64ba68c62c57852470ffc28e3db5";
536        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
537    }
538
539    #[test]
540    fn test_p2sh_p2wpkh_invalid() {
541        type N = Bitcoin;
542
543        // Invalid public key length
544
545        let public_key = "0";
546        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
547
548        let public_key = "02468791fee1444df3a6e786e2f9da79198";
549        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
550
551        let public_key = "02468791fee1444df3a6e786e2f9da79198f8902387e1fa5a2c051950c4df51ab";
552        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
553
554        let public_key =
555            "02468791fee1444df3a6e786e2f9da79198f8902387e1fa5a2c051950c4df51ab402468791fee1444df3a6e786e2f9da79198";
556        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
557
558        let public_key = "02468791fee1444df3a6e786e2f9da79198f8902387e1fa5a2c051950c4df51ab402468791fee1444df3a6e786e2f9da79198f8902387e1fa5a2c051950c4df51ab4";
559        assert!(BitcoinPublicKey::<N>::from_str(public_key).is_err());
560    }
561}