1use crate::{BitcoinAddress, BitcoinFormat, BitcoinNetwork};
2use anychain_core::{hex, Address, AddressError, PublicKey, PublicKeyError};
3use core::{fmt, marker::PhantomData, str::FromStr};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct BitcoinPublicKey<N: BitcoinNetwork> {
8 public_key: libsecp256k1::PublicKey,
10 compressed: bool,
12 _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 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 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 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 pub fn to_secp256k1_public_key(&self) -> libsecp256k1::PublicKey {
51 self.public_key
52 }
53
54 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 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 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 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}