1use std::convert::{TryFrom as _, TryInto as _};
19use std::error;
20use std::fmt;
21use std::fmt::Write as _;
22use std::str::FromStr;
23
24use bech32::{Bech32, Bech32m, ByteIterExt, Fe32, Fe32IterExt, Hrp};
25use crate::blech32::{Blech32, Blech32m};
26use bitcoin::base58;
27use bitcoin::hashes::Hash as _;
28use bitcoin::PublicKey;
29use internals::array::ArrayExt as _;
30use internals::slice::SliceExt;
31use secp256k1_zkp;
32use secp256k1_zkp::Secp256k1;
33use secp256k1_zkp::Verification;
34#[cfg(feature = "serde")]
35use serde;
36
37use crate::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey};
38use crate::taproot::TapNodeHash;
39
40use crate::{opcodes, script};
41use crate::{PubkeyHash, ScriptHash, WScriptHash};
42
43#[derive(Debug, PartialEq)]
45pub enum AddressError {
46 Base58(base58::Error),
48 Bech32(bech32::primitives::decode::SegwitHrpstringError),
50 Blech32(crate::blech32::decode::SegwitHrpstringError),
52 InvalidAddress(String),
54 InvalidWitnessVersion(u8),
56 InvalidWitnessProgramLength(usize),
58 InvalidSegwitV0ProgramLength(usize),
60 InvalidWitnessEncoding,
62 InvalidSegwitV0Encoding,
64
65 InvalidBlindingPubKey(secp256k1_zkp::UpstreamError),
67
68 InvalidLength(usize),
70
71 InvalidAddressVersion(u8),
73}
74
75impl From<bech32::primitives::decode::SegwitHrpstringError> for AddressError {
76 fn from(e: bech32::primitives::decode::SegwitHrpstringError) -> Self {
77 AddressError::Bech32(e)
78 }
79}
80
81impl From<crate::blech32::decode::SegwitHrpstringError> for AddressError {
82 fn from(e: crate::blech32::decode::SegwitHrpstringError) -> Self {
83 AddressError::Blech32(e)
84 }
85}
86
87impl fmt::Display for AddressError {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 match *self {
90 AddressError::Base58(ref e) => write!(f, "base58 error: {}", e),
91 AddressError::Bech32(ref e) => write!(f, "bech32 error: {}", e),
92 AddressError::Blech32(ref e) => write!(f, "blech32 error: {}", e),
93 AddressError::InvalidAddress(ref a) => {
94 write!(f, "was unable to parse the address: {}", a)
95 }
96 AddressError::InvalidWitnessVersion(ref wver) => {
97 write!(f, "invalid witness script version: {}", wver)
98 }
99 AddressError::InvalidWitnessProgramLength(ref len) => {
100 write!(
101 f,
102 "the witness program must be between 2 and 40 bytes in length, not {}",
103 len
104 )
105 }
106 AddressError::InvalidSegwitV0ProgramLength(ref len) => {
107 write!(
108 f,
109 "a v0 witness program must be length 20 or 32, not {}",
110 len
111 )
112 }
113 AddressError::InvalidBlindingPubKey(ref e) => {
114 write!(f, "an invalid blinding pubkey was encountered: {}", e)
115 }
116 AddressError::InvalidWitnessEncoding => {
117 write!(f, "v1+ witness program must use b(l)ech32m not b(l)ech32")
118 }
119 AddressError::InvalidSegwitV0Encoding => {
120 write!(f, "v0 witness program must use b(l)ech32 not b(l)ech32m")
121 }
122 AddressError::InvalidLength(len) => {
123 write!(f, "Address data has invalid length {}", len)
124 }
125 AddressError::InvalidAddressVersion(v) => {
126 write!(f, "address version {} is invalid for this type", v)
127 }
128 }
129 }
130}
131
132impl error::Error for AddressError {
133 fn cause(&self) -> Option<&dyn error::Error> {
134 match *self {
135 AddressError::Base58(ref e) => Some(e),
136 AddressError::Bech32(ref e) => Some(e),
137 AddressError::Blech32(ref e) => Some(e),
138 AddressError::InvalidBlindingPubKey(ref e) => Some(e),
139 _ => None,
140 }
141 }
142}
143
144#[doc(hidden)]
145impl From<base58::Error> for AddressError {
146 fn from(e: base58::Error) -> AddressError {
147 AddressError::Base58(e)
148 }
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
153pub struct AddressParams {
154 pub p2pkh_prefix: u8,
156 pub p2sh_prefix: u8,
158 pub blinded_prefix: u8,
160 pub bech_hrp: Hrp,
162 pub blech_hrp: Hrp,
164}
165
166impl AddressParams {
167 pub const LIQUID: AddressParams = AddressParams {
169 p2pkh_prefix: 57,
170 p2sh_prefix: 39,
171 blinded_prefix: 12,
172 bech_hrp: Hrp::parse_unchecked("ex"),
173 blech_hrp: Hrp::parse_unchecked("lq"),
174 };
175
176 pub const ELEMENTS: AddressParams = AddressParams {
178 p2pkh_prefix: 235,
179 p2sh_prefix: 75,
180 blinded_prefix: 4,
181 bech_hrp: Hrp::parse_unchecked("ert"),
182 blech_hrp: Hrp::parse_unchecked("el"),
183 };
184
185 pub const LIQUID_TESTNET: AddressParams = AddressParams {
187 p2pkh_prefix: 36,
188 p2sh_prefix: 19,
189 blinded_prefix: 23,
190 bech_hrp: Hrp::parse_unchecked("tex"),
191 blech_hrp: Hrp::parse_unchecked("tlq"),
192 };
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Hash)]
197pub enum Payload {
198 PubkeyHash(PubkeyHash),
200 ScriptHash(ScriptHash),
202 WitnessProgram {
204 version: Fe32,
206 program: Vec<u8>,
208 },
209}
210
211#[derive(Clone, PartialEq, Eq, Hash)]
213pub struct Address {
214 pub params: &'static AddressParams,
216 pub payload: Payload,
218 pub blinding_pubkey: Option<secp256k1_zkp::PublicKey>,
220}
221
222impl Address {
223 pub fn is_blinded(&self) -> bool {
225 self.blinding_pubkey.is_some()
226 }
227
228 pub fn is_liquid(&self) -> bool {
230 self.params == &AddressParams::LIQUID
231 }
232
233 #[inline]
236 pub fn p2pkh(
237 pk: &PublicKey,
238 blinder: Option<secp256k1_zkp::PublicKey>,
239 params: &'static AddressParams,
240 ) -> Address {
241 Address {
242 params,
243 payload: Payload::PubkeyHash(pk.pubkey_hash()),
244 blinding_pubkey: blinder,
245 }
246 }
247
248 #[inline]
251 pub fn p2sh(
252 script: &script::Script,
253 blinder: Option<secp256k1_zkp::PublicKey>,
254 params: &'static AddressParams,
255 ) -> Address {
256 Address {
257 params,
258 payload: Payload::ScriptHash(ScriptHash::hash_script(script)),
259 blinding_pubkey: blinder,
260 }
261 }
262
263 pub fn p2wpkh(
270 pk: &PublicKey,
271 blinder: Option<secp256k1_zkp::PublicKey>,
272 params: &'static AddressParams,
273 ) -> Address {
274 Address {
275 params,
276 payload: Payload::WitnessProgram {
277 version: Fe32::Q,
278 program: pk.wpubkey_hash().expect("public key must be compressed").as_byte_array().to_vec(),
279 },
280 blinding_pubkey: blinder,
281 }
282 }
283
284 pub fn p2shwpkh(
291 pk: &PublicKey,
292 blinder: Option<secp256k1_zkp::PublicKey>,
293 params: &'static AddressParams,
294 ) -> Address {
295 let pkh = pk.wpubkey_hash().expect("public key must be compressed");
296 let builder = script::Builder::new()
297 .push_int(0)
298 .push_slice(pkh.as_ref());
299
300 Address {
301 params,
302 payload: Payload::ScriptHash(ScriptHash::hash_script(&builder.into_script())),
303 blinding_pubkey: blinder,
304 }
305 }
306
307 pub fn p2wsh(
309 script: &script::Script,
310 blinder: Option<secp256k1_zkp::PublicKey>,
311 params: &'static AddressParams,
312 ) -> Address {
313 Address {
314 params,
315 payload: Payload::WitnessProgram {
316 version: Fe32::Q,
317 program: WScriptHash::hash_script(script).as_byte_array().to_vec(),
318 },
319 blinding_pubkey: blinder,
320 }
321 }
322
323 pub fn p2shwsh(
326 script: &script::Script,
327 blinder: Option<secp256k1_zkp::PublicKey>,
328 params: &'static AddressParams,
329 ) -> Address {
330 let ws = script::Builder::new()
331 .push_int(0)
332 .push_slice(WScriptHash::hash_script(script).as_ref())
333 .into_script();
334
335 Address {
336 params,
337 payload: Payload::ScriptHash(ScriptHash::hash_script(&ws)),
338 blinding_pubkey: blinder,
339 }
340 }
341
342 pub fn p2tr<C: Verification>(
344 secp: &Secp256k1<C>,
345 internal_key: UntweakedPublicKey,
346 merkle_root: Option<TapNodeHash>,
347 blinder: Option<secp256k1_zkp::PublicKey>,
348 params: &'static AddressParams,
349 ) -> Address {
350 Address {
351 params,
352 payload: {
353 let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
354 Payload::WitnessProgram {
355 version: Fe32::P,
356 program: output_key.into_inner().serialize().to_vec(),
357 }
358 },
359 blinding_pubkey: blinder,
360 }
361 }
362
363 pub fn p2tr_tweaked(
367 output_key: TweakedPublicKey,
368 blinder: Option<secp256k1_zkp::PublicKey>,
369 params: &'static AddressParams,
370 ) -> Address {
371 Address {
372 params,
373 payload: Payload::WitnessProgram {
374 version: Fe32::P,
375 program: output_key.into_inner().serialize().to_vec(),
376 },
377 blinding_pubkey: blinder,
378 }
379 }
380
381 pub fn from_script(
383 script: &script::Script,
384 blinder: Option<secp256k1_zkp::PublicKey>,
385 params: &'static AddressParams,
386 ) -> Option<Address> {
387 Some(Address {
388 payload: if script.is_p2pkh() {
389 Payload::PubkeyHash(PubkeyHash::from_byte_array(script.as_bytes()[3..23].try_into().unwrap()))
390 } else if script.is_p2sh() {
391 Payload::ScriptHash(ScriptHash::from_byte_array(script.as_bytes()[2..22].try_into().unwrap()))
392 } else if script.is_v0_p2wpkh() {
393 Payload::WitnessProgram {
394 version: Fe32::Q,
395 program: script.as_bytes()[2..22].to_vec(),
396 }
397 } else if script.is_v0_p2wsh() {
398 Payload::WitnessProgram {
399 version: Fe32::Q,
400 program: script.as_bytes()[2..34].to_vec(),
401 }
402 } else if script.is_v1plus_p2witprog() {
403 Payload::WitnessProgram {
404 version: Fe32::try_from(script.as_bytes()[0] - 0x50).expect("0<32"),
405 program: script.as_bytes()[2..].to_vec(),
406 }
407 } else {
408 return None;
409 },
410 blinding_pubkey: blinder,
411 params,
412 })
413 }
414
415 pub fn script_pubkey(&self) -> script::Script {
417 match self.payload {
418 Payload::PubkeyHash(ref hash) => script::Builder::new()
419 .push_opcode(opcodes::all::OP_DUP)
420 .push_opcode(opcodes::all::OP_HASH160)
421 .push_slice(hash.as_ref())
422 .push_opcode(opcodes::all::OP_EQUALVERIFY)
423 .push_opcode(opcodes::all::OP_CHECKSIG),
424 Payload::ScriptHash(ref hash) => script::Builder::new()
425 .push_opcode(opcodes::all::OP_HASH160)
426 .push_slice(hash.as_byte_array())
427 .push_opcode(opcodes::all::OP_EQUAL),
428 Payload::WitnessProgram {
429 version: witver,
430 program: ref witprog,
431 } => script::Builder::new()
432 .push_int(i64::from(witver.to_u8()))
433 .push_slice(witprog),
434 }
435 .into_script()
436 }
437
438 #[must_use]
440 pub fn to_unconfidential(&self) -> Address {
441 Address {
442 params: self.params,
443 payload: self.payload.clone(),
444 blinding_pubkey: None,
445 }
446 }
447
448 #[must_use]
450 pub fn to_confidential(&self, blinding_pubkey: secp256k1_zkp::PublicKey) -> Address {
451 Address {
452 params: self.params,
453 payload: self.payload.clone(),
454 blinding_pubkey: Some(blinding_pubkey),
455 }
456 }
457
458 fn from_bech32(
459 s: &str,
460 blinded: bool,
461 params: &'static AddressParams,
462 ) -> Result<Address, AddressError> {
463 let (version, data): (Fe32, Vec<u8>) = if blinded {
464 let hs = crate::blech32::decode::SegwitHrpstring::new(s)?;
465 (hs.witness_version(), hs.byte_iter().collect())
466 } else {
467 let hs = bech32::primitives::decode::SegwitHrpstring::new(s)?;
468 (hs.witness_version(), hs.byte_iter().collect())
469 };
470
471 let (blinding_pubkey, program) = match blinded {
472 true => {
473 let (pk, rest) = SliceExt::split_first_chunk::<33>(data.as_slice())
474 .ok_or(AddressError::InvalidSegwitV0Encoding)?;
475 (
476 Some(
477 secp256k1_zkp::PublicKey::from_slice(pk)
478 .map_err(AddressError::InvalidBlindingPubKey)?,
479 ),
480 rest.to_vec(),
481 )
482 },
483 false => (None, data),
484 };
485
486 Ok(Address {
487 params,
488 payload: Payload::WitnessProgram { version, program },
489 blinding_pubkey,
490 })
491 }
492
493 fn from_base58(data: &[u8], params: &'static AddressParams) -> Result<Address, AddressError> {
495 let len_error = AddressError::InvalidLength(data.len());
496 let Some((blinding_prefix, blinded_data)) = data.split_first() else {
502 return Err(len_error);
503 };
504
505 let (prefix, blinding_pubkey, hash) = if *blinding_prefix == params.blinded_prefix {
506 let Some((prefix, pubkey_and_hash)) = blinded_data.split_first() else {
507 return Err(len_error);
508 };
509
510 let pubkey_and_hash = <&[u8; 53]>::try_from(pubkey_and_hash).map_err(|_| len_error)?;
511 let (pubkey, hash) = pubkey_and_hash.split_array::<33, 20>();
512
513 let blinding_pubkey = secp256k1_zkp::PublicKey::from_slice(pubkey)
514 .map_err(AddressError::InvalidBlindingPubKey)?;
515
516 (prefix, Some(blinding_pubkey), hash)
517 } else {
518 let hash = <&[u8; 20]>::try_from(blinded_data).map_err(|_| len_error)?;
519 (blinding_prefix, None, hash)
520 };
521
522 let payload = if *prefix == params.p2pkh_prefix {
523 Payload::PubkeyHash(PubkeyHash::from_byte_array(*hash))
524 } else if *prefix == params.p2sh_prefix {
525 Payload::ScriptHash(ScriptHash::from_byte_array(*hash))
526 } else {
527 return Err(AddressError::InvalidAddressVersion(*prefix));
528 };
529
530 Ok(Address {
531 params,
532 payload,
533 blinding_pubkey,
534 })
535 }
536
537 pub fn parse_with_params(
540 s: &str,
541 params: &'static AddressParams,
542 ) -> Result<Address, AddressError> {
543 let prefix = find_prefix(s);
545 let b32_ex = match_prefix(prefix, params.bech_hrp);
546 let b32_bl = match_prefix(prefix, params.blech_hrp);
547 if b32_ex || b32_bl {
548 return Address::from_bech32(s, b32_bl, params);
549 }
550
551 if s.len() > 150 {
553 return Err(AddressError::InvalidLength(s.len() * 11 / 15));
554 }
555 let data = base58::decode_check(s)?;
556 Address::from_base58(&data, params)
557 }
558}
559
560impl fmt::Display for Address {
561 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
562 match self.payload {
563 Payload::PubkeyHash(ref hash) => {
564 if let Some(ref blinder) = self.blinding_pubkey {
565 let mut prefixed = [0; 55]; prefixed[0] = self.params.blinded_prefix;
567 prefixed[1] = self.params.p2pkh_prefix;
568 prefixed[2..35].copy_from_slice(&blinder.serialize());
569 prefixed[35..].copy_from_slice(hash.as_ref());
570 base58::encode_check_to_fmt(fmt, &prefixed[..])
571 } else {
572 let mut prefixed = [0; 21];
573 prefixed[0] = self.params.p2pkh_prefix;
574 prefixed[1..].copy_from_slice(hash.as_ref());
575 base58::encode_check_to_fmt(fmt, &prefixed[..])
576 }
577 }
578 Payload::ScriptHash(ref hash) => {
579 if let Some(ref blinder) = self.blinding_pubkey {
580 let mut prefixed = [0; 55]; prefixed[0] = self.params.blinded_prefix;
582 prefixed[1] = self.params.p2sh_prefix;
583 prefixed[2..35].copy_from_slice(&blinder.serialize());
584 prefixed[35..].copy_from_slice(hash.as_byte_array());
585 base58::encode_check_to_fmt(fmt, &prefixed[..])
586 } else {
587 let mut prefixed = [0; 21];
588 prefixed[0] = self.params.p2sh_prefix;
589 prefixed[1..].copy_from_slice(hash.as_byte_array());
590 base58::encode_check_to_fmt(fmt, &prefixed[..])
591 }
592 }
593 Payload::WitnessProgram {
594 version: witver,
595 program: ref witprog,
596 } => {
597 let hrp = match self.blinding_pubkey.is_some() {
598 true => self.params.blech_hrp,
599 false => self.params.bech_hrp,
600 };
601
602 if self.is_blinded() {
604 if let Some(ref blinder) = self.blinding_pubkey {
605 let byte_iter = IntoIterator::into_iter(blinder.serialize())
606 .chain(witprog.iter().copied());
607 let fe_iter = byte_iter.bytes_to_fes();
608 if witver.to_u8() == 0 {
609 for c in fe_iter
610 .with_checksum::<Blech32>(&hrp)
611 .with_witness_version(witver)
612 .chars()
613 {
614 fmt.write_char(c)?;
615 }
616 } else {
617 for c in fe_iter
618 .with_checksum::<Blech32m>(&hrp)
619 .with_witness_version(witver)
620 .chars()
621 {
622 fmt.write_char(c)?;
623 }
624 }
625 return Ok(());
626 }
627 }
628
629 let byte_iter = witprog.iter().copied();
630 let fe_iter = byte_iter.bytes_to_fes();
631 if witver.to_u8() == 0 {
632 for c in fe_iter
633 .with_checksum::<Bech32>(&hrp)
634 .with_witness_version(witver)
635 .chars()
636 {
637 fmt.write_char(c)?;
638 }
639 } else {
640 for c in fe_iter
641 .with_checksum::<Bech32m>(&hrp)
642 .with_witness_version(witver)
643 .chars()
644 {
645 fmt.write_char(c)?;
646 }
647 }
648 Ok(())
649 }
650 }
651 }
652}
653
654impl fmt::Debug for Address {
655 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
656 fmt::Display::fmt(self, fmt)
657 }
658}
659
660fn find_prefix(bech32: &str) -> &str {
663 match bech32.rfind('1') {
665 None => bech32,
666 Some(sep) => bech32.split_at(sep).0,
667 }
668}
669
670fn match_prefix(prefix_mixed: &str, target: Hrp) -> bool {
674 target.len() == prefix_mixed.len() && target
675 .lowercase_char_iter()
676 .zip(prefix_mixed.chars())
677 .all(|(char_lower, char_mixed)| char_lower == char_mixed.to_ascii_lowercase())
678}
679
680impl FromStr for Address {
681 type Err = AddressError;
682
683 fn from_str(s: &str) -> Result<Address, AddressError> {
684 let liq = &AddressParams::LIQUID;
686 let ele = &AddressParams::ELEMENTS;
687 let liq_test = &AddressParams::LIQUID_TESTNET;
688
689 let net_arr = [liq, ele, liq_test];
690
691 let prefix = find_prefix(s);
692 for net in &net_arr {
693 if match_prefix(prefix, net.bech_hrp) {
695 return Address::from_bech32(s, false, net);
696 }
697 if match_prefix(prefix, net.blech_hrp) {
698 return Address::from_bech32(s, true, net);
699 }
700 }
701
702 if s.len() > 150 {
704 return Err(AddressError::InvalidLength(s.len() * 11 / 15));
705 }
706 let data = base58::decode_check(s)?;
707 if data.is_empty() {
708 return Err(AddressError::InvalidLength(data.len()));
709 }
710
711 let p = data[0];
712 for net in &net_arr {
713 if p == net.p2pkh_prefix || p == net.p2sh_prefix || p == net.blinded_prefix {
714 return Address::from_base58(&data, net);
715 }
716 }
717
718 Err(AddressError::InvalidAddress(s.to_owned()))
719 }
720}
721
722#[cfg(feature = "serde")]
723impl<'de> serde::Deserialize<'de> for Address {
724 #[inline]
725 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
726 where
727 D: serde::Deserializer<'de>,
728 {
729 use std::fmt::Formatter;
730
731 struct Visitor;
732 impl<'de> serde::de::Visitor<'de> for Visitor {
733 type Value = Address;
734
735 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
736 formatter.write_str("a Bitcoin address")
737 }
738
739 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
740 where
741 E: serde::de::Error,
742 {
743 Address::from_str(v).map_err(E::custom)
744 }
745
746 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
747 where
748 E: serde::de::Error,
749 {
750 self.visit_str(v)
751 }
752
753 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
754 where
755 E: serde::de::Error,
756 {
757 self.visit_str(&v)
758 }
759 }
760
761 deserializer.deserialize_str(Visitor)
762 }
763}
764
765#[cfg(feature = "serde")]
766impl serde::Serialize for Address {
767 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
768 where
769 S: serde::Serializer,
770 {
771 serializer.serialize_str(&self.to_string())
772 }
773}
774
775#[cfg(test)]
776mod test {
777 use super::*;
778 use crate::Script;
779 use bitcoin::key;
780 use secp256k1_zkp::{PublicKey, Secp256k1};
781 #[cfg(feature = "serde")]
782 use serde_json;
783
784 fn roundtrips(addr: &Address) {
785 assert_eq!(
786 Address::from_str(&addr.to_string()).ok().as_ref(),
787 Some(addr),
788 "string round-trip failed for {}",
789 addr,
790 );
791 assert_eq!(
792 Address::from_script(&addr.script_pubkey(), addr.blinding_pubkey, addr.params).as_ref(),
793 Some(addr),
794 "script round-trip failed for {}",
795 addr,
796 );
797 #[cfg(feature = "serde")]
798 assert_eq!(
799 serde_json::from_value::<Address>(serde_json::to_value(addr).unwrap())
800 .ok()
801 .as_ref(),
802 Some(addr)
803 );
804 }
805
806 #[test]
807 fn regression_188() {
808 let addr = Address::from_str("tlq1qq2xvpcvfup5j8zscjq05u2wxxjcyewk7979f3mmz5l7uw5pqmx6xf5xy50hsn6vhkm5euwt72x878eq6zxx2z58hd7zrsg9qn").unwrap();
810 roundtrips(&addr);
811 }
812
813 #[test]
814 fn exhaustive() {
815 let blinder_hex = "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166";
816 let blinder = PublicKey::from_str(blinder_hex).unwrap();
817 let sk_wif = "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy";
818 let sk = key::PrivateKey::from_wif(sk_wif).unwrap();
819 let pk = sk.public_key(&Secp256k1::new());
820 let script: Script = vec![1u8, 2, 42, 255, 196].into();
821
822 let vectors = [
823 Address::p2pkh(&pk, None, &AddressParams::LIQUID),
824 Address::p2pkh(&pk, None, &AddressParams::ELEMENTS),
825 Address::p2pkh(&pk, Some(blinder), &AddressParams::LIQUID),
826 Address::p2pkh(&pk, Some(blinder), &AddressParams::ELEMENTS),
827 Address::p2sh(&script, None, &AddressParams::LIQUID),
828 Address::p2sh(&script, None, &AddressParams::ELEMENTS),
829 Address::p2sh(&script, Some(blinder), &AddressParams::LIQUID),
830 Address::p2sh(&script, Some(blinder), &AddressParams::ELEMENTS),
832 Address::p2wpkh(&pk, None, &AddressParams::LIQUID),
833 Address::p2wpkh(&pk, None, &AddressParams::ELEMENTS),
834 Address::p2wpkh(&pk, Some(blinder), &AddressParams::LIQUID),
835 Address::p2wpkh(&pk, Some(blinder), &AddressParams::ELEMENTS),
836 Address::p2shwpkh(&pk, None, &AddressParams::LIQUID),
837 Address::p2shwpkh(&pk, None, &AddressParams::ELEMENTS),
838 Address::p2shwpkh(&pk, Some(blinder), &AddressParams::LIQUID),
839 Address::p2shwpkh(&pk, Some(blinder), &AddressParams::ELEMENTS),
841 Address::p2wsh(&script, None, &AddressParams::LIQUID),
842 Address::p2wsh(&script, None, &AddressParams::ELEMENTS),
843 Address::p2wsh(&script, Some(blinder), &AddressParams::LIQUID),
844 Address::p2wsh(&script, Some(blinder), &AddressParams::ELEMENTS),
846 Address::p2shwsh(&script, None, &AddressParams::LIQUID),
847 Address::p2shwsh(&script, None, &AddressParams::ELEMENTS),
848 Address::p2shwsh(&script, Some(blinder), &AddressParams::LIQUID),
850 Address::p2shwsh(&script, Some(blinder), &AddressParams::ELEMENTS),
852 ];
853
854 for addr in &vectors {
855 roundtrips(addr);
856 }
857 }
858
859 #[test]
860 fn test_actuals() {
861 let addresses = [
863 ("2dxmEBXc2qMYcLSKiDBxdEePY3Ytixmnh4E", false, AddressParams::ELEMENTS),
865 ("CTEo6VKG8xbe7HnfVW9mQoWTgtgeRSPktwTLbELzGw5tV8Ngzu53EBiasFMQKVbWmKWWTAdN5AUf4M6Y", true, AddressParams::ELEMENTS),
866 ("ert1qwhh2n5qypypm0eufahm2pvj8raj9zq5c27cysu", false, AddressParams::ELEMENTS),
867 ("el1qq0umk3pez693jrrlxz9ndlkuwne93gdu9g83mhhzuyf46e3mdzfpva0w48gqgzgrklncnm0k5zeyw8my2ypfsmxh4xcjh2rse", true, AddressParams::ELEMENTS),
868 ("GqiQRsPEyJLAsEBFB5R34KHuqxDNkG3zur", false, AddressParams::LIQUID),
870 ("VJLDwMVWXg8RKq4mRe3YFNTAEykVN6V8x5MRUKKoC3nfRnbpnZeiG3jygMC6A4Gw967GY5EotJ4Rau2F", true, AddressParams::LIQUID),
871 ("ex1q7gkeyjut0mrxc3j0kjlt7rmcnvsh0gt45d3fud", false, AddressParams::LIQUID),
872 ("lq1qqf8er278e6nyvuwtgf39e6ewvdcnjupn9a86rzpx655y5lhkt0walu3djf9cklkxd3ryld97hu8h3xepw7sh2rlu7q45dcew5", true, AddressParams::LIQUID),
873 ];
874
875 for &(a, blinded, ref params) in &addresses {
876 let result = a.parse();
877 assert!(
878 result.is_ok(),
879 "vector: {}, err: \"{}\"",
880 a,
881 result.unwrap_err()
882 );
883 let addr: Address = result.unwrap();
884 assert_eq!(a, &addr.to_string(), "vector: {}", a);
885 assert_eq!(blinded, addr.is_blinded());
886 assert_eq!(params, addr.params);
887 roundtrips(&addr);
888 }
889 }
890
891 #[test]
892 fn test_blech32_vectors() {
893 let address: Result<Address, _> = "el1qq0umk3pez693jrrlxz9ndlkuwne93gdu9g83mhhzuyf46e3mdzfpva0w48gqgzgrklncnm0k5zeyw8my2ypfsmxh4xcjh2rse".parse();
895 assert!(address.is_ok());
896
897 let address: Result<Address, _> = "el1pq0umk3pez693jrrlxz9ndlkuwne93gdu9g83mhhzuyf46e3mdzfpva0w48gqgzgrklncnm0k5zeyw8my2ypfsxguu9nrdg2pc".parse();
898 assert_eq!(
899 address.err().unwrap().to_string(),
900 "blech32 error: invalid checksum", );
902
903 let address: Result<Address, _> = "el1qq0umk3pez693jrrlxz9ndlkuwne93gdu9g83mhhzuyf46e3mdzfpva0w48gqgzgrklncnm0k5zeyw8my2ypfsnnmzrstzt7de".parse();
904 assert_eq!(
905 address.err().unwrap().to_string(),
906 "blech32 error: invalid checksum", );
908
909 let address: Result<Address, _> =
910 "ert130xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqqu2tys".parse();
911 assert_eq!(
912 address.err().unwrap().to_string(),
913 "bech32 error: invalid segwit witness version: 17 (bech32 character: '3')",
914 );
915
916 let address: Result<Address, _> = "el1pq0umk3pez693jrrlxz9ndlkuwne93gdu9g83mhhzuyf46e3mdzfpva0w48gqgzgrklncnm0k5zeyw8my2ypfsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpe9jfn0gypaj".parse();
917 assert_eq!(
918 address.err().unwrap().to_string(),
919 "blech32 error: invalid witness length",
920 );
921
922 let address: Result<Address, _> = "rrr1qq0umk3pez693jrrlxz9ndlkuwne93gdu9g83mhhzuyf46e3mdzfpva0w48gqgzgrklncnm0k5zeyw8my2ypfs2d9rp7meq4kg".parse();
925 assert_eq!(address.err().unwrap().to_string(), "base58 error: decode",);
926 }
927
928 #[test]
929 fn test_fixed_addresses() {
930 let pk = bitcoin::PublicKey::from_str(
931 "0212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea",
932 )
933 .unwrap();
934 let script = Script::default();
935 let secp = Secp256k1::verification_only();
936 let internal_key = UntweakedPublicKey::from_str(
937 "93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51",
938 )
939 .unwrap();
940 let tap_node_hash = TapNodeHash::from_byte_array([0; 32]);
941
942 let mut expected = IntoIterator::into_iter([
943 "2dszRCFv8Ub4ytKo1Q1vXXGgSx7mekNDwSJ",
944 "XToMocNywBYNSiXUe5xvoa2naAps9Ek1hq",
945 "ert1qew0l0emv7449u7hqgc8utzdzryhse79yhq2sxv",
946 "XZF6k8S6eoVxXMB4NpWjh2s7LjQUP7pw2R",
947 "ert1quwcvgs5clswpfxhm7nyfjmaeysn6us0yvjdexn9yjkv3k7zjhp2szaqlpq",
948 "ert1p8qs0qcn25l2y6yvtc5t95rr8w9pndcj64c8rkutnvkcvdp6gh02q2cqvj9",
949 "ert1pxrrurkg8j8pve97lffvv2y67cf7ux478h077c87qacqzhue7390sqkjp06",
950 "CTEkC79sYAvWNcxd8iTYnYo226FqRBbzBcMppq7L2dA8jVXJWoo1kKWB3UBLY6gBjiXf87ibs8c6mQyZ",
951 "AzpjUhKMLJi9y2oLt3ZdM3BP9nHdLPJfGMVxRBaRc2gDpeNqPMVpShTszJW7bX42vT2KoejYy8GtbcxH",
952 "el1qqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww4jul7lnkeat2teawq3s0cky6yxf0pnu2gmz9ej9kyq5yc",
953 "AzpjUhKMLJi9y2oLt3ZdM3BP9nHdLPJfGMVxRBaRc2gDpeNvq6SLVpBVwtakF6nmUFundyW7YjUdVkpr",
954 "el1qqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww4casc3pf3lquzjd0haxgn9hmjfp84eq7geymjdx2f9verdu99wz4h79u87cnxdzq",
955 "el1pqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww5wpq7p3x4f75f5gch3gktgxxwu2rxm394tsw8dchxedsc6r53w75cj24fq2u2ls5",
956 "el1pqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww5vx8c8vs0ywzejta7jjcc5f4asnacdtu0wlaas0upmsq90enaz2lhjd0k0q7qn4h",
957 "QFq3vvrr6Ub2KAyb3LdoCxEQvKukB6nN9i",
958 "GydeMhecNgrq17WMkyyTM4ETv1YubMVtLN",
959 "ex1qew0l0emv7449u7hqgc8utzdzryhse79ydjqgek",
960 "H55PJDhj6JpR5k9wViXGEX4nga8WmhXtnD",
961 "ex1quwcvgs5clswpfxhm7nyfjmaeysn6us0yvjdexn9yjkv3k7zjhp2s4sla8h",
962 "ex1p8qs0qcn25l2y6yvtc5t95rr8w9pndcj64c8rkutnvkcvdp6gh02qa4lw5j",
963 "ex1pxrrurkg8j8pve97lffvv2y67cf7ux478h077c87qacqzhue7390shmdrfd",
964 "VTptY6cqJbusNpL5xvo8VL38nLX9PGDjfYQfqhu9EaA7FtuidkWyQzMHY9jzZrpBcCXT437vM6V4N8kh",
965 "VJL64Ep3rcngP4cScRme15q9i8MCNiuqWeiG3YbtduUidVyorg7nRsgmmF714QtH3sNpWB2CqsVVciQh",
966 "lq1qqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww4jul7lnkeat2teawq3s0cky6yxf0pnu2gs2923tg58xcz",
967 "VJL64Ep3rcngP4cScRme15q9i8MCNiuqWeiG3YbtduUidVyuJR4JUzQPiqBdhzd1bgGHLVnmRUjfHc68",
968 "lq1qqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww4casc3pf3lquzjd0haxgn9hmjfp84eq7geymjdx2f9verdu99wz47jmkmgmr9a4s",
969 "lq1pqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww5wpq7p3x4f75f5gch3gktgxxwu2rxm394tsw8dchxedsc6r53w75375l4kfvf08y",
970 "lq1pqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww5vx8c8vs0ywzejta7jjcc5f4asnacdtu0wlaas0upmsq90enaz2l77n92erwrrz8",
971 "FojPFeboBgrd953mXXe72KWthjVwHWozqN",
972 "8vsafXgrB5bJeSidGbK5eYnjKvQ3RiB4BB",
973 "tex1qew0l0emv7449u7hqgc8utzdzryhse79yh5jp9a",
974 "92KKc3jxthYtj5ND1KrtY1d46UyeWV6XbP",
975 "tex1quwcvgs5clswpfxhm7nyfjmaeysn6us0yvjdexn9yjkv3k7zjhp2s5fd6kc",
976 "tex1p8qs0qcn25l2y6yvtc5t95rr8w9pndcj64c8rkutnvkcvdp6gh02quvdf9a",
977 "tex1pxrrurkg8j8pve97lffvv2y67cf7ux478h077c87qacqzhue7390skzlycz",
978 "vtS71VhcpFt978sha5d1L2gCzp3UL5kXacRpb3N4GTW5MwvBzz5HwxYyB8Pns4yM2dd2osmQkHSkp88u",
979 "vjTuLJ76nGi8PUopBVmGK8bLKPfBpaBWf6wKfn8z9Vdz6ubVhpvmMr6TK2RcqAYiujN1g1uwg8kejrM3",
980 "tlq1qqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww4jul7lnkeat2teawq3s0cky6yxf0pnu2gq8g2kuxfj8ft",
981 "vjTuLJ76nGi8PUopBVmGK8bLKPfBpaBWf6wKfn8z9Vdz6ubb9ZsHQxp5GcWFUkHTTYFUWLgWFk1DN5Fe",
982 "tlq1qqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww4casc3pf3lquzjd0haxgn9hmjfp84eq7geymjdx2f9verdu99wz4e6vcdfcyp5m8",
983 "tlq1pqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww5wpq7p3x4f75f5gch3gktgxxwu2rxm394tsw8dchxedsc6r53w75kkr3rh2tdxfn",
984 "tlq1pqgft7r4ytdenml0gaj67393sd3qkt3nxex0ut5dt3plhzwf6jaww5vx8c8vs0ywzejta7jjcc5f4asnacdtu0wlaas0upmsq90enaz2lekytucqf82vs",
985 ]);
986
987 for params in [
988 &AddressParams::ELEMENTS,
989 &AddressParams::LIQUID,
990 &AddressParams::LIQUID_TESTNET,
991 ] {
992 for blinder in [None, Some(pk.inner)] {
993 let addr = Address::p2pkh(&pk, blinder, params);
994 assert_eq!(&addr.to_string(), expected.next().unwrap());
995
996 let addr = Address::p2sh(&script, blinder, params);
997 assert_eq!(&addr.to_string(), expected.next().unwrap());
998
999 let addr = Address::p2wpkh(&pk, blinder, params);
1000 assert_eq!(&addr.to_string(), expected.next().unwrap());
1001
1002 let addr = Address::p2shwpkh(&pk, blinder, params);
1003 assert_eq!(&addr.to_string(), expected.next().unwrap());
1004
1005 let addr = Address::p2wsh(&script, blinder, params);
1006 assert_eq!(&addr.to_string(), expected.next().unwrap());
1007
1008 let addr = Address::p2tr(&secp, internal_key, None, blinder, params);
1009 assert_eq!(&addr.to_string(), expected.next().unwrap());
1010
1011 let addr = Address::p2tr(&secp, internal_key, Some(tap_node_hash), blinder, params);
1012 assert_eq!(&addr.to_string(), expected.next().unwrap());
1013 }
1014 }
1015 }
1016}