1use prelude::*;
36
37use core::fmt;
38use core::num::ParseIntError;
39use core::str::FromStr;
40#[cfg(feature = "std")] use std::error;
41
42use secp256k1::{Secp256k1, Verification, XOnlyPublicKey};
43use bech32;
44use hashes::{sha256, Hash, HashEngine};
45use hash_types::{PubkeyHash, ScriptHash};
46use blockdata::{script, opcodes};
47use blockdata::constants::{PUBKEY_ADDRESS_PREFIX_MAIN, SCRIPT_ADDRESS_PREFIX_MAIN, PUBKEY_ADDRESS_PREFIX_TEST, SCRIPT_ADDRESS_PREFIX_TEST, MAX_SCRIPT_ELEMENT_SIZE};
48use network::constants::Network;
49use util::base58;
50use util::taproot::TapBranchHash;
51use util::key::PublicKey;
52use blockdata::script::Instruction;
53use util::schnorr::{TapTweak, UntweakedPublicKey, TweakedPublicKey};
54
55#[derive(Debug, PartialEq, Eq, Clone)]
57pub enum Error {
58 Base58(base58::Error),
60 Bech32(bech32::Error),
62 EmptyBech32Payload,
64 InvalidBech32Variant {
66 expected: bech32::Variant,
68 found: bech32::Variant
70 },
71 InvalidWitnessVersion(u8),
73 UnparsableWitnessVersion(ParseIntError),
75 MalformedWitnessVersion,
77 InvalidWitnessProgramLength(usize),
79 InvalidSegwitV0ProgramLength(usize),
81 UncompressedPubkey,
83 ExcessiveScriptSize
85}
86
87impl fmt::Display for Error {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 match *self {
90 Error::Base58(_) => write!(f, "base58 address encoding error"),
91 Error::Bech32(_) => write!(f, "bech32 address encoding error"),
92 Error::EmptyBech32Payload => write!(f, "the bech32 payload was empty"),
93 Error::InvalidBech32Variant { expected, found } => write!(f, "invalid bech32 checksum variant found {:?} when {:?} was expected", found, expected),
94 Error::InvalidWitnessVersion(v) => write!(f, "invalid witness script version: {}", v),
95 Error::UnparsableWitnessVersion(_) => write!(f, "incorrect format of a witness version byte"),
96 Error::MalformedWitnessVersion => f.write_str("bitcoin script opcode does not match any known witness version, the script is malformed"),
97 Error::InvalidWitnessProgramLength(l) => write!(f, "the witness program must be between 2 and 40 bytes in length: length={}", l),
98 Error::InvalidSegwitV0ProgramLength(l) => write!(f, "a v0 witness program must be either of length 20 or 32 bytes: length={}", l),
99 Error::UncompressedPubkey => write!(f, "an uncompressed pubkey was used where it is not allowed"),
100 Error::ExcessiveScriptSize => write!(f, "Script size exceed 520 bytes"),
101 }
102 }
103}
104
105#[cfg(feature = "std")]
106#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
107impl ::std::error::Error for Error {
108 fn cause(&self) -> Option<&dyn error::Error> {
109 match *self {
110 Error::Base58(ref e) => Some(e),
111 Error::Bech32(ref e) => Some(e),
112 Error::UnparsableWitnessVersion(ref e) => Some(e),
113 _ => None,
114 }
115 }
116}
117
118#[doc(hidden)]
119impl From<base58::Error> for Error {
120 fn from(e: base58::Error) -> Error {
121 Error::Base58(e)
122 }
123}
124
125#[doc(hidden)]
126impl From<bech32::Error> for Error {
127 fn from(e: bech32::Error) -> Error {
128 Error::Bech32(e)
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
134pub enum AddressType {
135 P2pkh,
137 P2sh,
139 P2wpkh,
141 P2wsh,
143 P2tr,
145}
146
147impl fmt::Display for AddressType {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 f.write_str(match *self {
150 AddressType::P2pkh => "p2pkh",
151 AddressType::P2sh => "p2sh",
152 AddressType::P2wpkh => "p2wpkh",
153 AddressType::P2wsh => "p2wsh",
154 AddressType::P2tr => "p2tr",
155 })
156 }
157}
158
159impl FromStr for AddressType {
160 type Err = ();
161 fn from_str(s: &str) -> Result<Self, Self::Err> {
162 match s {
163 "p2pkh" => Ok(AddressType::P2pkh),
164 "p2sh" => Ok(AddressType::P2sh),
165 "p2wpkh" => Ok(AddressType::P2wpkh),
166 "p2wsh" => Ok(AddressType::P2wsh),
167 "p2tr" => Ok(AddressType::P2tr),
168 _ => Err(()),
169 }
170 }
171}
172
173#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
181#[repr(u8)]
182pub enum WitnessVersion {
183 V0 = 0,
185 V1 = 1,
187 V2 = 2,
189 V3 = 3,
191 V4 = 4,
193 V5 = 5,
195 V6 = 6,
197 V7 = 7,
199 V8 = 8,
201 V9 = 9,
203 V10 = 10,
205 V11 = 11,
207 V12 = 12,
209 V13 = 13,
211 V14 = 14,
213 V15 = 15,
215 V16 = 16,
217}
218
219impl fmt::Display for WitnessVersion {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 write!(f, "{}", *self as u8)
224 }
225}
226
227
228impl FromStr for WitnessVersion {
229 type Err = Error;
230
231 fn from_str(s: &str) -> Result<Self, Self::Err> {
232 let version = s.parse().map_err(Error::UnparsableWitnessVersion)?;
233 WitnessVersion::from_num(version)
234 }
235}
236
237impl WitnessVersion {
238 pub fn from_u5(value: ::bech32::u5) -> Result<Self, Error> {
248 WitnessVersion::from_num(value.to_u8())
249 }
250
251 pub fn from_num(no: u8) -> Result<Self, Error> {
260 Ok(match no {
261 0 => WitnessVersion::V0,
262 1 => WitnessVersion::V1,
263 2 => WitnessVersion::V2,
264 3 => WitnessVersion::V3,
265 4 => WitnessVersion::V4,
266 5 => WitnessVersion::V5,
267 6 => WitnessVersion::V6,
268 7 => WitnessVersion::V7,
269 8 => WitnessVersion::V8,
270 9 => WitnessVersion::V9,
271 10 => WitnessVersion::V10,
272 11 => WitnessVersion::V11,
273 12 => WitnessVersion::V12,
274 13 => WitnessVersion::V13,
275 14 => WitnessVersion::V14,
276 15 => WitnessVersion::V15,
277 16 => WitnessVersion::V16,
278 wrong => return Err(Error::InvalidWitnessVersion(wrong)),
279 })
280 }
281
282 pub fn from_opcode(opcode: opcodes::All) -> Result<Self, Error> {
291 match opcode.into_u8() {
292 0 => Ok(WitnessVersion::V0),
293 version if version >= opcodes::all::OP_PUSHNUM_1.into_u8() && version <= opcodes::all::OP_PUSHNUM_16.into_u8() =>
294 WitnessVersion::from_num(version - opcodes::all::OP_PUSHNUM_1.into_u8() + 1),
295 _ => Err(Error::MalformedWitnessVersion)
296 }
297 }
298
299 pub fn from_instruction(instruction: Instruction) -> Result<Self, Error> {
309 match instruction {
310 Instruction::Op(op) => WitnessVersion::from_opcode(op),
311 Instruction::PushBytes(bytes) if bytes.is_empty() => Ok(WitnessVersion::V0),
312 Instruction::PushBytes(_) => Err(Error::MalformedWitnessVersion),
313 }
314 }
315
316 pub fn into_num(self) -> u8 {
322 self as u8
323 }
324
325 pub fn bech32_variant(&self) -> bech32::Variant {
327 match self {
328 WitnessVersion::V0 => bech32::Variant::Bech32,
329 _ => bech32::Variant::Bech32m,
330 }
331 }
332}
333
334impl From<WitnessVersion> for ::bech32::u5 {
335 fn from(version: WitnessVersion) -> Self {
337 ::bech32::u5::try_from_u8(version.into_num()).expect("WitnessVersion must be 0..=16")
338 }
339}
340
341impl From<WitnessVersion> for opcodes::All {
342 fn from(version: WitnessVersion) -> opcodes::All {
344 match version {
345 WitnessVersion::V0 => opcodes::all::OP_PUSHBYTES_0,
346 no => opcodes::All::from(opcodes::all::OP_PUSHNUM_1.into_u8() + no.into_num() - 1)
347 }
348 }
349}
350
351#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
353pub enum Payload {
354 PubkeyHash(PubkeyHash),
356 ScriptHash(ScriptHash),
358 WitnessProgram {
360 version: WitnessVersion,
362 program: Vec<u8>,
364 },
365}
366
367impl Payload {
368 pub fn from_script(script: &script::Script) -> Option<Payload> {
370 Some(if script.is_p2pkh() {
371 let mut hash_inner = [0u8; 20];
372 hash_inner.copy_from_slice(&script.as_bytes()[3..23]);
373 Payload::PubkeyHash(PubkeyHash::from_inner(hash_inner))
374 } else if script.is_p2sh() {
375 let mut hash_inner = [0u8; 20];
376 hash_inner.copy_from_slice(&script.as_bytes()[2..22]);
377 Payload::ScriptHash(ScriptHash::from_inner(hash_inner))
378 } else if script.is_witness_program() {
379 Payload::WitnessProgram {
380 version: WitnessVersion::from_opcode(opcodes::All::from(script[0])).ok()?,
381 program: script[2..].to_vec(),
382 }
383 } else {
384 return None;
385 })
386 }
387
388 pub fn script_pubkey(&self) -> script::Script {
390 match *self {
391 Payload::PubkeyHash(ref hash) => script::Script::new_p2pkh(hash),
392 Payload::ScriptHash(ref hash) => script::Script::new_p2sh(hash),
393 Payload::WitnessProgram { version, program: ref prog } => {
394 script::Script::new_witness_program(version, prog)
395 }
396 }
397 }
398
399 #[inline]
401 pub fn p2pkh(pk: &PublicKey) -> Payload {
402 Payload::PubkeyHash(pk.pubkey_hash())
403 }
404
405 #[inline]
407 pub fn p2sh(script: &script::Script) -> Result<Payload, Error> {
408 if script.len() > MAX_SCRIPT_ELEMENT_SIZE {
409 return Err(Error::ExcessiveScriptSize);
410 }
411 Ok(Payload::ScriptHash(script.script_hash()))
412 }
413
414 pub fn p2wpkh(pk: &PublicKey) -> Result<Payload, Error> {
416 Ok(Payload::WitnessProgram {
417 version: WitnessVersion::V0,
418 program: pk.wpubkey_hash().ok_or(Error::UncompressedPubkey)?.to_vec(),
419 })
420 }
421
422 pub fn p2shwpkh(pk: &PublicKey) -> Result<Payload, Error> {
424 let builder = script::Builder::new()
425 .push_int(0)
426 .push_slice(&pk.wpubkey_hash().ok_or(Error::UncompressedPubkey)?);
427
428 Ok(Payload::ScriptHash(builder.into_script().script_hash()))
429 }
430
431 pub fn p2wsh(script: &script::Script) -> Payload {
433 Payload::WitnessProgram {
434 version: WitnessVersion::V0,
435 program: script.wscript_hash().to_vec(),
436 }
437 }
438
439 pub fn p2shwsh(script: &script::Script) -> Payload {
441 let ws = script::Builder::new()
442 .push_int(0)
443 .push_slice(&script.wscript_hash())
444 .into_script();
445
446 Payload::ScriptHash(ws.script_hash())
447 }
448
449 pub fn p2tr<C: Verification>(
451 secp: &Secp256k1<C>,
452 internal_key: UntweakedPublicKey,
453 merkle_root: Option<TapBranchHash>,
454 ) -> Payload {
455 let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
456 Payload::WitnessProgram {
457 version: WitnessVersion::V1,
458 program: output_key.to_inner().serialize().to_vec(),
459 }
460 }
461
462 pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Payload {
466 Payload::WitnessProgram {
467 version: WitnessVersion::V1,
468 program: output_key.as_inner().serialize().to_vec(),
469 }
470 }
471}
472
473pub struct AddressEncoding<'a> {
476 pub payload: &'a Payload,
478 pub p2pkh_prefix: u8,
480 pub p2sh_prefix: u8,
482 pub bech32_hrp: &'a str,
484}
485
486impl<'a> fmt::Display for AddressEncoding<'a> {
487 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
488 match self.payload {
489 Payload::PubkeyHash(hash) => {
490 let mut prefixed = [0; 21];
491 prefixed[0] = self.p2pkh_prefix;
492 prefixed[1..].copy_from_slice(&hash[..]);
493 base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
494 }
495 Payload::ScriptHash(hash) => {
496 let mut prefixed = [0; 21];
497 prefixed[0] = self.p2sh_prefix;
498 prefixed[1..].copy_from_slice(&hash[..]);
499 base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
500 }
501 Payload::WitnessProgram {
502 version,
503 program: prog,
504 } => {
505 let mut upper_writer;
506 let writer = if fmt.alternate() {
507 upper_writer = UpperWriter(fmt);
508 &mut upper_writer as &mut dyn fmt::Write
509 } else {
510 fmt as &mut dyn fmt::Write
511 };
512 let mut bech32_writer =
513 bech32::Bech32Writer::new(self.bech32_hrp, version.bech32_variant(), writer)?;
514 bech32::WriteBase32::write_u5(&mut bech32_writer, (*version).into())?;
515 bech32::ToBase32::write_base32(&prog, &mut bech32_writer)
516 }
517 }
518 }
519}
520
521#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
523pub struct Address {
524 pub payload: Payload,
526 pub network: Network,
528}
529serde_string_impl!(Address, "a Bitcoin address");
530
531impl Address {
532 #[inline]
536 pub fn p2pkh(pk: &PublicKey, network: Network) -> Address {
537 Address {
538 network,
539 payload: Payload::p2pkh(pk),
540 }
541 }
542
543 #[inline]
548 pub fn p2sh(script: &script::Script, network: Network) -> Result<Address, Error> {
549 Ok(Address {
550 network,
551 payload: Payload::p2sh(script)?,
552 })
553 }
554
555 pub fn p2wpkh(pk: &PublicKey, network: Network) -> Result<Address, Error> {
562 Ok(Address {
563 network,
564 payload: Payload::p2wpkh(pk)?,
565 })
566 }
567
568 pub fn p2shwpkh(pk: &PublicKey, network: Network) -> Result<Address, Error> {
575 Ok(Address {
576 network,
577 payload: Payload::p2shwpkh(pk)?,
578 })
579 }
580
581 pub fn p2wsh(script: &script::Script, network: Network) -> Address {
583 Address {
584 network,
585 payload: Payload::p2wsh(script),
586 }
587 }
588
589 pub fn p2shwsh(script: &script::Script, network: Network) -> Address {
593 Address {
594 network,
595 payload: Payload::p2shwsh(script),
596 }
597 }
598
599 pub fn p2tr<C: Verification>(
601 secp: &Secp256k1<C>,
602 internal_key: UntweakedPublicKey,
603 merkle_root: Option<TapBranchHash>,
604 network: Network
605 ) -> Address {
606 Address {
607 network: network,
608 payload: Payload::p2tr(secp, internal_key, merkle_root),
609 }
610 }
611
612 pub fn p2tr_tweaked(output_key: TweakedPublicKey, network: Network) -> Address {
616 Address {
617 network,
618 payload: Payload::p2tr_tweaked(output_key),
619 }
620 }
621
622 pub fn address_type(&self) -> Option<AddressType> {
627 match self.payload {
628 Payload::PubkeyHash(_) => Some(AddressType::P2pkh),
629 Payload::ScriptHash(_) => Some(AddressType::P2sh),
630 Payload::WitnessProgram {
631 version,
632 program: ref prog,
633 } => {
634 match version {
636 WitnessVersion::V0 => match prog.len() {
637 20 => Some(AddressType::P2wpkh),
638 32 => Some(AddressType::P2wsh),
639 _ => None,
640 },
641 WitnessVersion::V1 if prog.len() == 32 => Some(AddressType::P2tr),
642 _ => None,
643 }
644 }
645 }
646 }
647
648 pub fn is_standard(&self) -> bool {
653 self.address_type().is_some()
654 }
655
656 pub fn from_script(script: &script::Script, network: Network) -> Option<Address> {
658 Some(Address {
659 payload: Payload::from_script(script)?,
660 network,
661 })
662 }
663
664 pub fn script_pubkey(&self) -> script::Script {
666 self.payload.script_pubkey()
667 }
668
669 pub fn to_qr_uri(&self) -> String {
677 let schema = match self.payload {
678 Payload::WitnessProgram { .. } => "BITCOIN",
679 _ => "bitcoin",
680 };
681 format!("{}:{:#}", schema, self)
682 }
683
684 pub fn is_valid_for_network(&self, network: Network) -> bool {
705 let is_legacy = match self.address_type() {
706 Some(AddressType::P2pkh) | Some(AddressType::P2sh) => true,
707 _ => false
708 };
709
710 match (self.network, network) {
711 (a, b) if a == b => true,
712 (Network::Bitcoin, _) | (_, Network::Bitcoin) => false,
713 (Network::Regtest, _) | (_, Network::Regtest) if !is_legacy => false,
714 (Network::Testnet, _) | (Network::Regtest, _) | (Network::Signet, _) => true
715 }
716 }
717
718 pub fn is_related_to_pubkey(&self, pubkey: &PublicKey) -> bool {
724 let pubkey_hash = pubkey.pubkey_hash();
725 let payload = self.payload_as_bytes();
726 let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner);
727
728 (*pubkey_hash == *payload) || (xonly_pubkey.serialize() == *payload) || (*segwit_redeem_hash(&pubkey_hash) == *payload)
729 }
730
731 pub fn is_related_to_xonly_pubkey(&self, xonly_pubkey: &XOnlyPublicKey) -> bool {
736 let payload = self.payload_as_bytes();
737 payload == xonly_pubkey.serialize()
738 }
739
740 fn payload_as_bytes(&self) -> &[u8] {
742 match &self.payload {
743 Payload::ScriptHash(hash) => hash,
744 Payload::PubkeyHash(hash) => hash,
745 Payload::WitnessProgram { program, .. } => program,
746 }
747 }
748}
749
750impl fmt::Display for Address {
753 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
754 let p2pkh_prefix = match self.network {
755 Network::Bitcoin => PUBKEY_ADDRESS_PREFIX_MAIN,
756 Network::Testnet | Network::Signet | Network::Regtest => PUBKEY_ADDRESS_PREFIX_TEST,
757 };
758 let p2sh_prefix = match self.network {
759 Network::Bitcoin => SCRIPT_ADDRESS_PREFIX_MAIN,
760 Network::Testnet | Network::Signet | Network::Regtest => SCRIPT_ADDRESS_PREFIX_TEST,
761 };
762 let bech32_hrp = match self.network {
763 Network::Bitcoin => "bc",
764 Network::Testnet | Network::Signet => "tb",
765 Network::Regtest => "bcrt",
766 };
767 let encoding = AddressEncoding {
768 payload: &self.payload,
769 p2pkh_prefix,
770 p2sh_prefix,
771 bech32_hrp,
772 };
773 encoding.fmt(fmt)
774 }
775}
776
777struct UpperWriter<W: fmt::Write>(W);
778
779impl<W: fmt::Write> fmt::Write for UpperWriter<W> {
780 fn write_str(&mut self, s: &str) -> fmt::Result {
781 for c in s.chars() {
782 self.0.write_char(c.to_ascii_uppercase())?;
783 }
784 Ok(())
785 }
786}
787
788fn find_bech32_prefix(bech32: &str) -> &str {
793 match bech32.rfind('1') {
795 None => bech32,
796 Some(sep) => bech32.split_at(sep).0,
797 }
798}
799
800impl FromStr for Address {
801 type Err = Error;
802
803 fn from_str(s: &str) -> Result<Address, Error> {
804 let bech32_network = match find_bech32_prefix(s) {
806 "bc" | "BC" => Some(Network::Bitcoin),
808 "tb" | "TB" => Some(Network::Testnet), "bcrt" | "BCRT" => Some(Network::Regtest),
810 _ => None,
811 };
812 if let Some(network) = bech32_network {
813 let (_, payload, variant) = bech32::decode(s)?;
815 if payload.is_empty() {
816 return Err(Error::EmptyBech32Payload);
817 }
818
819 let (version, program): (WitnessVersion, Vec<u8>) = {
821 let (v, p5) = payload.split_at(1);
822 (WitnessVersion::from_u5(v[0])?, bech32::FromBase32::from_base32(p5)?)
823 };
824
825 if program.len() < 2 || program.len() > 40 {
826 return Err(Error::InvalidWitnessProgramLength(program.len()));
827 }
828
829 if version == WitnessVersion::V0 && (program.len() != 20 && program.len() != 32) {
831 return Err(Error::InvalidSegwitV0ProgramLength(program.len()));
832 }
833
834 let expected = version.bech32_variant();
836 if expected != variant {
837 return Err(Error::InvalidBech32Variant { expected, found: variant });
838 }
839
840 return Ok(Address {
841 payload: Payload::WitnessProgram {
842 version,
843 program,
844 },
845 network,
846 });
847 }
848
849 if s.len() > 50 {
851 return Err(Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15)));
852 }
853 let data = base58::from_check(s)?;
854 if data.len() != 21 {
855 return Err(Error::Base58(base58::Error::InvalidLength(data.len())));
856 }
857
858 let (network, payload) = match data[0] {
859 PUBKEY_ADDRESS_PREFIX_MAIN => (
860 Network::Bitcoin,
861 Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap()),
862 ),
863 SCRIPT_ADDRESS_PREFIX_MAIN => (
864 Network::Bitcoin,
865 Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap()),
866 ),
867 PUBKEY_ADDRESS_PREFIX_TEST => (
868 Network::Testnet,
869 Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap()),
870 ),
871 SCRIPT_ADDRESS_PREFIX_TEST => (
872 Network::Testnet,
873 Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap()),
874 ),
875 x => return Err(Error::Base58(base58::Error::InvalidAddressVersion(x))),
876 };
877
878 Ok(Address {
879 network,
880 payload,
881 })
882 }
883}
884
885impl fmt::Debug for Address {
886 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
887 fmt::Display::fmt(self, f)
888 }
889}
890
891fn segwit_redeem_hash(pubkey_hash: &[u8]) -> ::hashes::hash160::Hash {
893 let mut sha_engine = sha256::Hash::engine();
894 sha_engine.input(&[0, 20]);
895 sha_engine.input(pubkey_hash);
896 ::hashes::hash160::Hash::from_engine(sha_engine)
897}
898
899#[cfg(test)]
900mod tests {
901 use core::str::FromStr;
902
903 use hashes::hex::{FromHex, ToHex};
904
905 use blockdata::script::Script;
906 use network::constants::Network::{Bitcoin, Testnet};
907 use util::key::PublicKey;
908 use secp256k1::XOnlyPublicKey;
909
910 use super::*;
911
912 macro_rules! hex (($hex:expr) => (Vec::from_hex($hex).unwrap()));
913 macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($hex)).unwrap()));
914 macro_rules! hex_script (($hex:expr) => (Script::from(hex!($hex))));
915 macro_rules! hex_pubkeyhash (($hex:expr) => (PubkeyHash::from_hex(&$hex).unwrap()));
916 macro_rules! hex_scripthash (($hex:expr) => (ScriptHash::from_hex($hex).unwrap()));
917
918 fn roundtrips(addr: &Address) {
919 assert_eq!(
920 Address::from_str(&addr.to_string()).unwrap(),
921 *addr,
922 "string round-trip failed for {}",
923 addr,
924 );
925 assert_eq!(
926 Address::from_script(&addr.script_pubkey(), addr.network).as_ref(),
927 Some(addr),
928 "script round-trip failed for {}",
929 addr,
930 );
931 }
933
934 #[test]
935 fn test_p2pkh_address_58() {
936 let addr = Address {
937 network: Bitcoin,
938 payload: Payload::PubkeyHash(hex_pubkeyhash!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")),
939 };
940
941 assert_eq!(
942 addr.script_pubkey(),
943 hex_script!("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac")
944 );
945 assert_eq!(&addr.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
946 assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
947 roundtrips(&addr);
948 }
949
950 #[test]
951 fn test_p2pkh_from_key() {
952 let key = hex_key!("048d5141948c1702e8c95f438815794b87f706a8d4cd2bffad1dc1570971032c9b6042a0431ded2478b5c9cf2d81c124a5e57347a3c63ef0e7716cf54d613ba183");
953 let addr = Address::p2pkh(&key, Bitcoin);
954 assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY");
955
956 let key = hex_key!(&"03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f");
957 let addr = Address::p2pkh(&key, Testnet);
958 assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC");
959 assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
960 roundtrips(&addr);
961 }
962
963 #[test]
964 fn test_p2sh_address_58() {
965 let addr = Address {
966 network: Bitcoin,
967 payload: Payload::ScriptHash(hex_scripthash!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")),
968 };
969
970 assert_eq!(
971 addr.script_pubkey(),
972 hex_script!("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087")
973 );
974 assert_eq!(&addr.to_string(), "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k");
975 assert_eq!(addr.address_type(), Some(AddressType::P2sh));
976 roundtrips(&addr);
977 }
978
979 #[test]
980 fn test_p2sh_parse() {
981 let script = hex_script!("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae");
982 let addr = Address::p2sh(&script, Testnet).unwrap();
983 assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr");
984 assert_eq!(addr.address_type(), Some(AddressType::P2sh));
985 roundtrips(&addr);
986 }
987
988 #[test]
989 fn test_p2sh_parse_for_large_script(){
990 let script = hex_script!("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123");
991 assert_eq!(Address::p2sh(&script, Testnet), Err(Error::ExcessiveScriptSize));
992 }
993
994 #[test]
995 fn test_p2wpkh() {
996 let mut key = hex_key!("033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc");
998 let addr = Address::p2wpkh(&key, Bitcoin).unwrap();
999 assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw");
1000 assert_eq!(addr.address_type(), Some(AddressType::P2wpkh));
1001 roundtrips(&addr);
1002
1003 key.compressed = false;
1005 assert_eq!(Address::p2wpkh(&key, Bitcoin), Err(Error::UncompressedPubkey));
1006 }
1007
1008 #[test]
1009 fn test_p2wsh() {
1010 let script = hex_script!("52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae");
1012 let addr = Address::p2wsh(&script, Bitcoin);
1013 assert_eq!(
1014 &addr.to_string(),
1015 "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej"
1016 );
1017 assert_eq!(addr.address_type(), Some(AddressType::P2wsh));
1018 roundtrips(&addr);
1019 }
1020
1021 #[test]
1022 fn test_p2shwpkh() {
1023 let mut key = hex_key!("026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766");
1025 let addr = Address::p2shwpkh(&key, Bitcoin).unwrap();
1026 assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE");
1027 assert_eq!(addr.address_type(), Some(AddressType::P2sh));
1028 roundtrips(&addr);
1029
1030 key.compressed = false;
1032 assert_eq!(Address::p2wpkh(&key, Bitcoin), Err(Error::UncompressedPubkey));
1033 }
1034
1035 #[test]
1036 fn test_p2shwsh() {
1037 let script = hex_script!("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae");
1039 let addr = Address::p2shwsh(&script, Bitcoin);
1040 assert_eq!(&addr.to_string(), "36EqgNnsWW94SreZgBWc1ANC6wpFZwirHr");
1041 assert_eq!(addr.address_type(), Some(AddressType::P2sh));
1042 roundtrips(&addr);
1043 }
1044
1045 #[test]
1046 fn test_non_existent_segwit_version() {
1047 let program = hex!(
1049 "654f6ea368e0acdfd92976b7c2103a1b26313f430654f6ea368e0acdfd92976b7c2103a1b26313f4"
1050 );
1051 let addr = Address {
1052 payload: Payload::WitnessProgram {
1053 version: WitnessVersion::V13,
1054 program: program,
1055 },
1056 network: Network::Bitcoin,
1057 };
1058 roundtrips(&addr);
1059 }
1060
1061 #[test]
1062 fn test_address_type() {
1063 let addresses = [
1064 ("1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY", Some(AddressType::P2pkh)),
1065 ("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k", Some(AddressType::P2sh)),
1066 ("bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw", Some(AddressType::P2wpkh)),
1067 ("bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej", Some(AddressType::P2wsh)),
1068 ("bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr", Some(AddressType::P2tr)),
1069 ("bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", None),
1072 ("bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", None),
1074 ];
1075 for (address, expected_type) in &addresses {
1076 let addr = Address::from_str(&address).unwrap();
1077 assert_eq!(&addr.address_type(), expected_type);
1078 }
1079 }
1080
1081 #[test]
1082 fn test_bip173_350_vectors() {
1083 let valid_vectors = [
1085 ("BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6"),
1086 ("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"),
1087 ("bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"),
1088 ("BC1SW50QGDZ25J", "6002751e"),
1089 ("bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", "5210751e76e8199196d454941c45d1b3a323"),
1090 ("tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"),
1091 ("tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"),
1092 ("bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")
1093 ];
1094 for vector in &valid_vectors {
1095 let addr: Address = vector.0.parse().unwrap();
1096 assert_eq!(&addr.script_pubkey().as_bytes().to_hex(), vector.1);
1097 roundtrips(&addr);
1098 }
1099
1100 let invalid_vectors = [
1101 "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
1104 "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
1106 "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf",
1107 "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
1108 "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh",
1109 "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47",
1110 "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
1112 "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
1114 "bc1pw5dgrnzv",
1116 "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav",
1118 "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
1120 "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
1122 "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf",
1124 "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
1126 "bc1gmk9yu",
1128
1129 "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
1132 "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
1134 "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
1136 "bc1rw5uspcuh",
1138 "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
1140 "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
1142 "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
1144 "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
1146 "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
1148 "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
1152 "BC1SW50QA3JX3S",
1153 "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
1154 ];
1155 for vector in &invalid_vectors {
1156 assert!(vector.parse::<Address>().is_err());
1157 }
1158 }
1159
1160 #[test]
1161 #[cfg(feature = "serde")]
1162 fn test_json_serialize() {
1163 use serde_json;
1164
1165 let addr = Address::from_str("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM").unwrap();
1166 let json = serde_json::to_value(&addr).unwrap();
1167 assert_eq!(
1168 json,
1169 serde_json::Value::String("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".to_owned())
1170 );
1171 let into: Address = serde_json::from_value(json).unwrap();
1172 assert_eq!(addr.to_string(), into.to_string());
1173 assert_eq!(
1174 into.script_pubkey(),
1175 hex_script!("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac")
1176 );
1177
1178 let addr = Address::from_str("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k").unwrap();
1179 let json = serde_json::to_value(&addr).unwrap();
1180 assert_eq!(
1181 json,
1182 serde_json::Value::String("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k".to_owned())
1183 );
1184 let into: Address = serde_json::from_value(json).unwrap();
1185 assert_eq!(addr.to_string(), into.to_string());
1186 assert_eq!(
1187 into.script_pubkey(),
1188 hex_script!("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087")
1189 );
1190
1191 let addr =
1192 Address::from_str("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
1193 .unwrap();
1194 let json = serde_json::to_value(&addr).unwrap();
1195 assert_eq!(
1196 json,
1197 serde_json::Value::String(
1198 "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7".to_owned()
1199 )
1200 );
1201 let into: Address = serde_json::from_value(json).unwrap();
1202 assert_eq!(addr.to_string(), into.to_string());
1203 assert_eq!(
1204 into.script_pubkey(),
1205 hex_script!("00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262")
1206 );
1207
1208 let addr = Address::from_str("bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl").unwrap();
1209 let json = serde_json::to_value(&addr).unwrap();
1210 assert_eq!(
1211 json,
1212 serde_json::Value::String("bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl".to_owned())
1213 );
1214 let into: Address = serde_json::from_value(json).unwrap();
1215 assert_eq!(addr.to_string(), into.to_string());
1216 assert_eq!(
1217 into.script_pubkey(),
1218 hex_script!("001454d26dddb59c7073c6a197946ea1841951fa7a74")
1219 );
1220 }
1221
1222 #[test]
1223 fn test_qr_string() {
1224 for el in ["132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM", "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k"].iter() {
1225 let addr = Address::from_str(el).unwrap();
1226 assert_eq!(addr.to_qr_uri(), format!("litcoinlib:{}", el));
1227 }
1228
1229 for el in ["bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl", "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej"].iter() {
1230 let addr = Address::from_str(el).unwrap();
1231 assert_eq!(addr.to_qr_uri(), format!("litcoinlib:{}", el.to_ascii_uppercase()) );
1232 }
1233 }
1234
1235 #[test]
1236 fn test_valid_networks() {
1237 let legacy_payload = &[
1238 Payload::PubkeyHash(PubkeyHash::default()),
1239 Payload::ScriptHash(ScriptHash::default())
1240 ];
1241 let segwit_payload = (0..=16).map(|version| {
1242 Payload::WitnessProgram {
1243 version: WitnessVersion::from_num(version).unwrap(),
1244 program: vec![]
1245 }
1246 }).collect::<Vec<_>>();
1247
1248 const LEGACY_EQUIVALENCE_CLASSES: &[&[Network]] = &[
1249 &[Network::Bitcoin],
1250 &[Network::Testnet, Network::Regtest, Network::Signet],
1251 ];
1252 const SEGWIT_EQUIVALENCE_CLASSES: &[&[Network]] = &[
1253 &[Network::Bitcoin],
1254 &[Network::Regtest],
1255 &[Network::Testnet, Network::Signet],
1256 ];
1257
1258 fn test_addr_type(payloads: &[Payload], equivalence_classes: &[&[Network]]) {
1259 for pl in payloads {
1260 for addr_net in equivalence_classes.iter().map(|ec| ec.iter()).flatten() {
1261 for valid_net in equivalence_classes.iter()
1262 .filter(|ec| ec.contains(addr_net))
1263 .map(|ec| ec.iter())
1264 .flatten()
1265 {
1266 let addr = Address {
1267 payload: pl.clone(),
1268 network: *addr_net
1269 };
1270 assert!(addr.is_valid_for_network(*valid_net));
1271 }
1272
1273 for invalid_net in equivalence_classes.iter()
1274 .filter(|ec| !ec.contains(addr_net))
1275 .map(|ec| ec.iter())
1276 .flatten()
1277 {
1278 let addr = Address {
1279 payload: pl.clone(),
1280 network: *addr_net
1281 };
1282 assert!(!addr.is_valid_for_network(*invalid_net));
1283 }
1284 }
1285 }
1286 }
1287
1288 test_addr_type(legacy_payload, LEGACY_EQUIVALENCE_CLASSES);
1289 test_addr_type(&segwit_payload, SEGWIT_EQUIVALENCE_CLASSES);
1290 }
1291
1292 #[test]
1293 fn p2tr_from_untweaked() {
1294 let internal_key = XOnlyPublicKey::from_str("cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115").unwrap();
1296 let secp = Secp256k1::verification_only();
1297 let address = Address::p2tr(&secp, internal_key, None, Network::Bitcoin);
1298 assert_eq!(address.to_string(), "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr");
1299 assert_eq!(address.address_type(), Some(AddressType::P2tr));
1300 roundtrips(&address);
1301 }
1302
1303 #[test]
1304 fn test_is_related_to_pubkey_p2wpkh() {
1305 let address_string = "bc1qhvd6suvqzjcu9pxjhrwhtrlj85ny3n2mqql5w4";
1306 let address = Address::from_str(address_string).expect("address");
1307
1308 let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b";
1309 let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
1310
1311 let result = address.is_related_to_pubkey(&pubkey);
1312 assert!(result);
1313
1314 let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey");
1315 assert!(!address.is_related_to_pubkey(&unused_pubkey))
1316 }
1317
1318 #[test]
1319 fn test_is_related_to_pubkey_p2shwpkh() {
1320 let address_string = "3EZQk4F8GURH5sqVMLTFisD17yNeKa7Dfs";
1321 let address = Address::from_str(address_string).expect("address");
1322
1323 let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b";
1324 let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
1325
1326 let result = address.is_related_to_pubkey(&pubkey);
1327 assert!(result);
1328
1329 let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey");
1330 assert!(!address.is_related_to_pubkey(&unused_pubkey))
1331 }
1332
1333 #[test]
1334 fn test_is_related_to_pubkey_p2pkh() {
1335 let address_string = "1J4LVanjHMu3JkXbVrahNuQCTGCRRgfWWx";
1336 let address = Address::from_str(address_string).expect("address");
1337
1338 let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b";
1339 let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
1340
1341 let result = address.is_related_to_pubkey(&pubkey);
1342 assert!(result);
1343
1344 let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey");
1345 assert!(!address.is_related_to_pubkey(&unused_pubkey))
1346 }
1347
1348 #[test]
1349 fn test_is_related_to_pubkey_p2pkh_uncompressed_key() {
1350 let address_string = "msvS7KzhReCDpQEJaV2hmGNvuQqVUDuC6p";
1351 let address = Address::from_str(address_string).expect("address");
1352
1353 let pubkey_string = "04e96e22004e3db93530de27ccddfdf1463975d2138ac018fc3e7ba1a2e5e0aad8e424d0b55e2436eb1d0dcd5cb2b8bcc6d53412c22f358de57803a6a655fbbd04";
1354 let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
1355
1356 let result = address.is_related_to_pubkey(&pubkey);
1357 assert!(result);
1358
1359 let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey");
1360 assert!(!address.is_related_to_pubkey(&unused_pubkey))
1361 }
1362
1363 #[test]
1364 fn test_is_related_to_pubkey_p2tr(){
1365 let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b";
1366 let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
1367 let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner);
1368 let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(xonly_pubkey);
1369 let address = Address::p2tr_tweaked(tweaked_pubkey, Network::Bitcoin);
1370
1371 assert_eq!(address, Address::from_str("bc1pgllnmtxs0g058qz7c6qgaqq4qknwrqj9z7rqn9e2dzhmcfmhlu4sfadf5e").expect("address"));
1372
1373 let result = address.is_related_to_pubkey(&pubkey);
1374 assert!(result);
1375
1376 let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey");
1377 assert!(!address.is_related_to_pubkey(&unused_pubkey));
1378 }
1379
1380 #[test]
1381 fn test_is_related_to_xonly_pubkey(){
1382 let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b";
1383 let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey");
1384 let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner);
1385 let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(xonly_pubkey);
1386 let address = Address::p2tr_tweaked(tweaked_pubkey, Network::Bitcoin);
1387
1388 assert_eq!(address, Address::from_str("bc1pgllnmtxs0g058qz7c6qgaqq4qknwrqj9z7rqn9e2dzhmcfmhlu4sfadf5e").expect("address"));
1389
1390 let result = address.is_related_to_xonly_pubkey(&xonly_pubkey);
1391 assert!(result);
1392 }
1393}