bech32/primitives/
decode.rs

1// SPDX-License-Identifier: MIT
2
3//! Decoding of bech32 encoded strings as specified by [BIP-173] and [BIP-350].
4//!
5//! You should only need to use this module directly if you want control over exactly what is
6//! checked and when it is checked (correct bech32 characters, valid checksum, valid checksum for
7//! specific checksum algorithm, etc). If you are parsing/validating modern (post BIP-350) bitcoin
8//! segwit addresses consider using the [`crate::segwit`] API.
9//!
10//! If you do find yourself using this module directly then consider using the most general type
11//! that serves your purposes, each type can be created by parsing an address string to `new`. You
12//! likely do not want to arbitrarily transition from one type to the next even though possible. And
13//! be prepared to spend some time with the bips - you have been warned :)
14//!
15//! # Details
16//!
17//! A Bech32 string is at most 90 characters long and consists of:
18//!
19//! - The human-readable part, which is intended to convey the type of data, or anything else that
20//!   is relevant to the reader. This part MUST contain 1 to 83 US-ASCII characters.
21//! - The separator, which is always "1".
22//! - The data part, which is at least 6 characters long and only consists of alphanumeric
23//!   characters excluding "1", "b", "i", and "o".
24//!
25//! The types in this module heavily lean on the wording in BIP-173: *We first
26//! describe the general checksummed base32 format called Bech32 and then define Segregated Witness
27//! addresses using it.*
28//!
29//! - `UncheckedHrpstring`: Parses the general checksummed base32 format and provides checksum validation.
30//! - `CheckedHrpstring`: Provides access to the data encoded by a general checksummed base32 string and segwit checks.
31//! - `SegwitHrpstring`: Provides access to the data encoded by a segwit address.
32//!
33//! # Examples
34//!
35//! ```
36//! use bech32::{Bech32, Bech32m, Fe32, Hrp};
37//! use bech32::primitives::decode::{CheckedHrpstring, SegwitHrpstring, UncheckedHrpstring};
38//! use bech32::segwit::VERSION_1;
39//!
40//! // An arbitrary HRP and a string of valid bech32 characters.
41//! let s = "abcd143hj65vxw49rts6kcw35u6r6tgzguyr03vvveeewjqpn05efzq444444";
42//! assert!(UncheckedHrpstring::new(s).is_ok());
43//! // But it has an invalid checksum.
44//! assert!(CheckedHrpstring::new::<Bech32>(s).is_err());
45//! assert!(CheckedHrpstring::new::<Bech32m>(s).is_err());
46//! assert!(SegwitHrpstring::new(s).is_err());
47//!
48//! // An arbitrary HRP, a string of valid bech32 characters, and a valid bech32 checksum.
49//! let s = "abcd14g08d6qejxtdg4y5r3zarvary0c5xw7kxugcx9";
50//! assert!(UncheckedHrpstring::new(s).is_ok());
51//! assert!(CheckedHrpstring::new::<Bech32>(s).is_ok());
52//! // But not a valid segwit address.
53//! assert!(SegwitHrpstring::new(s).is_err());
54//! // And not a valid bech32m checksum.
55//! assert!(CheckedHrpstring::new::<Bech32m>(s).is_err());
56//!
57//! // A valid Bitcoin taproot address.
58//! let s = "bc1pdp43hj65vxw49rts6kcw35u6r6tgzguyr03vvveeewjqpn05efzq7un9w0";
59//! assert!(UncheckedHrpstring::new(s).is_ok());
60//! assert!(CheckedHrpstring::new::<Bech32m>(s).is_ok());
61//! assert!(SegwitHrpstring::new(s).is_ok());
62//! // But not a valid segwit v0 checksum.
63//! assert!(CheckedHrpstring::new::<Bech32>(s).is_err());
64//!
65//! // Get the HRP, witness version, and encoded data.
66//! let address = "bc1pdp43hj65vxw49rts6kcw35u6r6tgzguyr03vvveeewjqpn05efzq7un9w0";
67//! let segwit = SegwitHrpstring::new(address).expect("valid segwit address");
68//! let _encoded_data = segwit.byte_iter();
69//! assert_eq!(segwit.hrp(), Hrp::parse("bc").unwrap());
70//! assert_eq!(segwit.witness_version(), VERSION_1);
71//! ```
72//!
73//! [BIP-173]: <https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki>
74//! [BIP-350]: <https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki>
75
76use core::{fmt, iter, slice, str};
77
78use crate::error::write_err;
79use crate::primitives::checksum::{self, Checksum};
80use crate::primitives::gf32::Fe32;
81use crate::primitives::hrp::{self, Hrp};
82use crate::primitives::iter::{Fe32IterExt, FesToBytes};
83use crate::primitives::segwit::{self, WitnessLengthError, VERSION_0};
84use crate::{Bech32, Bech32m};
85
86/// Separator between the hrp and payload (as defined by BIP-173).
87const SEP: char = '1';
88
89/// An HRP string that has been parsed but not yet had the checksum checked.
90///
91/// Parsing an HRP string only checks validity of the characters, it does not validate the
92/// checksum in any way.
93///
94/// Unless you are attempting to validate a string with multiple checksums then you likely do not
95/// want to use this type directly, instead use [`CheckedHrpstring::new(s)`].
96///
97/// # Examples
98///
99/// ```
100/// use bech32::{Bech32, Bech32m, primitives::decode::UncheckedHrpstring};
101///
102/// let addr = "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4";
103/// let unchecked = UncheckedHrpstring::new(addr).expect("valid bech32 character encoded string");
104/// if unchecked.has_valid_checksum::<Bech32>() {
105///     // Remove the checksum and do something with the data.
106///     let checked = unchecked.remove_checksum::<Bech32>();
107///     let _ = checked.byte_iter();
108/// } else if unchecked.has_valid_checksum::<Bech32m>() {
109///     // Remove the checksum and do something with the data as above.
110/// } else {
111///     // Checksum is not valid for either the bech32 or bech32 checksum algorithms.
112/// }
113/// ```
114#[derive(Debug)]
115pub struct UncheckedHrpstring<'s> {
116    /// The human-readable part, guaranteed to be lowercase ASCII characters.
117    hrp: Hrp,
118    /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters.
119    ///
120    /// The characters after the separator i.e., the "data part" defined by BIP-173.
121    data_part_ascii: &'s [u8],
122    /// The length of the parsed hrpstring.
123    hrpstring_length: usize,
124}
125
126impl<'s> UncheckedHrpstring<'s> {
127    /// Parses an bech32 encode string and constructs a [`UncheckedHrpstring`] object.
128    ///
129    /// Checks for valid ASCII values, does not validate the checksum.
130    #[inline]
131    pub fn new(s: &'s str) -> Result<Self, UncheckedHrpstringError> {
132        let sep_pos = check_characters(s)?;
133        let (hrp, rest) = s.split_at(sep_pos);
134
135        let ret = UncheckedHrpstring {
136            hrp: Hrp::parse(hrp)?,
137            data_part_ascii: rest[1..].as_bytes(), // Skip the separator.
138            hrpstring_length: s.len(),
139        };
140
141        Ok(ret)
142    }
143
144    /// Returns the human-readable part.
145    #[inline]
146    pub fn hrp(&self) -> Hrp { self.hrp }
147
148    /// Returns the data part as ASCII bytes i.e., everything after the separator '1'.
149    ///
150    /// The byte values are guaranteed to be valid bech32 characters. Includes the checksum
151    /// if one was present in the parsed string.
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// use bech32::primitives::decode::UncheckedHrpstring;
157    ///
158    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
159    /// let ascii = "qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
160    ///
161    /// let unchecked = UncheckedHrpstring::new(&addr).unwrap();
162    /// assert!(unchecked.data_part_ascii().iter().eq(ascii.as_bytes().iter()))
163    /// ```
164    #[inline]
165    pub fn data_part_ascii(&self) -> &'s [u8] { self.data_part_ascii }
166
167    /// Attempts to remove the first byte of the data part, treating it as a witness version.
168    ///
169    /// If [`Self::witness_version`] succeeds this function removes the first character (witness
170    /// version byte) from the internal ASCII data part buffer. Future calls to
171    /// [`Self::data_part_ascii`] will no longer include it.
172    ///
173    /// # Examples
174    ///
175    /// ```
176    /// use bech32::{primitives::decode::UncheckedHrpstring, Fe32};
177    ///
178    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
179    /// let ascii = "ar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
180    ///
181    /// let mut unchecked = UncheckedHrpstring::new(&addr).unwrap();
182    /// let witness_version = unchecked.remove_witness_version().unwrap();
183    /// assert_eq!(witness_version, Fe32::Q);
184    /// assert!(unchecked.data_part_ascii().iter().eq(ascii.as_bytes().iter()))
185    /// ```
186    #[inline]
187    pub fn remove_witness_version(&mut self) -> Option<Fe32> {
188        self.witness_version().map(|witver| {
189            self.data_part_ascii = &self.data_part_ascii[1..]; // Remove the witness version byte.
190            witver
191        })
192    }
193
194    /// Returns the segwit witness version if there is one.
195    ///
196    /// Attempts to convert the first character of the data part to a witness version. If this
197    /// succeeds, and it is a valid version (0..16 inclusive) we return it, otherwise `None`.
198    ///
199    /// Future calls to [`Self::data_part_ascii`] will still include the witness version, use
200    /// [`Self::remove_witness_version`] to remove it.
201    ///
202    /// This function makes no guarantees on the validity of the checksum.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use bech32::{primitives::decode::UncheckedHrpstring, Fe32};
208    ///
209    /// // Note the invalid checksum!
210    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzffffff";
211    ///
212    /// let unchecked = UncheckedHrpstring::new(&addr).unwrap();
213    /// assert_eq!(unchecked.witness_version(), Some(Fe32::Q));
214    /// ```
215    #[inline]
216    pub fn witness_version(&self) -> Option<Fe32> {
217        let data_part = self.data_part_ascii();
218        if data_part.is_empty() {
219            return None;
220        }
221
222        // unwrap ok because we know we gave valid bech32 characters.
223        let witness_version = Fe32::from_char(data_part[0].into()).unwrap();
224        if witness_version.to_u8() > 16 {
225            return None;
226        }
227        Some(witness_version)
228    }
229
230    /// Validates that data has a valid checksum for the `Ck` algorithm and returns a [`CheckedHrpstring`].
231    #[inline]
232    pub fn validate_and_remove_checksum<Ck: Checksum>(
233        self,
234    ) -> Result<CheckedHrpstring<'s>, ChecksumError> {
235        self.validate_checksum::<Ck>()?;
236        Ok(self.remove_checksum::<Ck>())
237    }
238
239    /// Validates that data has a valid checksum for the `Ck` algorithm (this may mean an empty
240    /// checksum if `NoChecksum` is used).
241    ///
242    /// This is useful if you do not know which checksum algorithm was used and wish to validate
243    /// against multiple algorithms consecutively. If this function returns `true` then call
244    /// `remove_checksum` to get a [`CheckedHrpstring`].
245    #[inline]
246    pub fn has_valid_checksum<Ck: Checksum>(&self) -> bool {
247        self.validate_checksum::<Ck>().is_ok()
248    }
249
250    /// Validates that data has a valid checksum for the `Ck` algorithm (this may mean an empty
251    /// checksum if `NoChecksum` is used).
252    #[inline]
253    pub fn validate_checksum<Ck: Checksum>(&self) -> Result<(), ChecksumError> {
254        use ChecksumError::*;
255
256        if self.hrpstring_length > Ck::CODE_LENGTH {
257            return Err(ChecksumError::CodeLength(CodeLengthError {
258                encoded_length: self.hrpstring_length,
259                code_length: Ck::CODE_LENGTH,
260            }));
261        }
262
263        if Ck::CHECKSUM_LENGTH == 0 {
264            // Called with NoChecksum
265            return Ok(());
266        }
267
268        if self.data_part_ascii.len() < Ck::CHECKSUM_LENGTH {
269            return Err(InvalidLength);
270        }
271
272        let mut checksum_eng = checksum::Engine::<Ck>::new();
273        checksum_eng.input_hrp(self.hrp());
274
275        // Unwrap ok since we checked all characters in our constructor.
276        for fe in self.data_part_ascii.iter().map(|&b| Fe32::from_char_unchecked(b)) {
277            checksum_eng.input_fe(fe);
278        }
279
280        if checksum_eng.residue() != &Ck::TARGET_RESIDUE {
281            return Err(InvalidResidue);
282        }
283
284        Ok(())
285    }
286
287    /// Removes the checksum for the `Ck` algorithm and returns an [`CheckedHrpstring`].
288    ///
289    /// Data must be valid (ie, first call `has_valid_checksum` or `validate_checksum()`). This
290    /// function is typically paired with `has_valid_checksum` when validating against multiple
291    /// checksum algorithms consecutively.
292    ///
293    /// # Panics
294    ///
295    /// May panic if data is not valid.
296    #[inline]
297    pub fn remove_checksum<Ck: Checksum>(self) -> CheckedHrpstring<'s> {
298        let end = self.data_part_ascii.len() - Ck::CHECKSUM_LENGTH;
299
300        CheckedHrpstring {
301            hrp: self.hrp(),
302            ascii: &self.data_part_ascii[..end],
303            hrpstring_length: self.hrpstring_length,
304        }
305    }
306}
307
308/// An HRP string that has been parsed and had the checksum validated.
309///
310/// This type does not treat the first byte of the data part in any special way i.e., as the witness
311/// version byte. If you are parsing Bitcoin segwit addresses consider using [`SegwitHrpstring`].
312///
313/// > We first describe the general checksummed base32 format called Bech32 and then
314/// > define Segregated Witness addresses using it.
315///
316/// This type abstracts over the general checksummed base32 format called Bech32.
317///
318/// # Examples
319///
320/// ```
321/// use bech32::{Bech32m, primitives::decode::CheckedHrpstring};
322///
323/// // Parse a general checksummed bech32 encoded string.
324/// let s = "abcd14g08d6qejxtdg4y5r3zarvary0c5xw7knqc5r8";
325/// let checked = CheckedHrpstring::new::<Bech32m>(s)
326///       .expect("valid bech32 string with a valid checksum according to the bech32m algorithm");
327///
328/// // Do something with the encoded data.
329/// let _ = checked.byte_iter();
330/// ```
331#[derive(Debug)]
332pub struct CheckedHrpstring<'s> {
333    /// The human-readable part, guaranteed to be lowercase ASCII characters.
334    hrp: Hrp,
335    /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters.
336    ///
337    /// The characters after the '1' separator and the before the checksum.
338    ascii: &'s [u8],
339    /// The length of the parsed hrpstring.
340    hrpstring_length: usize, // Guaranteed to be <= CK::CODE_LENGTH
341}
342
343impl<'s> CheckedHrpstring<'s> {
344    /// Parses and validates an HRP string, without treating the first data character specially.
345    ///
346    /// If you are validating the checksum multiple times consider using [`UncheckedHrpstring`].
347    ///
348    /// This is equivalent to `UncheckedHrpstring::new().validate_and_remove_checksum::<CK>()`.
349    #[inline]
350    pub fn new<Ck: Checksum>(s: &'s str) -> Result<Self, CheckedHrpstringError> {
351        let unchecked = UncheckedHrpstring::new(s)?;
352        let checked = unchecked.validate_and_remove_checksum::<Ck>()?;
353        Ok(checked)
354    }
355
356    /// Returns the human-readable part.
357    #[inline]
358    pub fn hrp(&self) -> Hrp { self.hrp }
359
360    /// Returns a partial slice of the data part, as ASCII bytes, everything after the separator '1'
361    /// before the checksum.
362    ///
363    /// The byte values are guaranteed to be valid bech32 characters.
364    ///
365    /// # Examples
366    ///
367    /// ```
368    /// use bech32::{Bech32, primitives::decode::CheckedHrpstring};
369    ///
370    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
371    /// let ascii = "qar0srrr7xfkvy5l643lydnw9re59gtzz";
372    ///
373    /// let checked = CheckedHrpstring::new::<Bech32>(&addr).unwrap();
374    /// assert!(checked.data_part_ascii_no_checksum().iter().eq(ascii.as_bytes().iter()))
375    /// ```
376    #[inline]
377    pub fn data_part_ascii_no_checksum(&self) -> &'s [u8] { self.ascii }
378
379    /// Attempts to remove the first byte of the data part, treating it as a witness version.
380    ///
381    /// If [`Self::witness_version`] succeeds this function removes the first character (witness
382    /// version byte) from the internal ASCII data part buffer. Future calls to
383    /// [`Self::data_part_ascii_no_checksum`] will no longer include it.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// use bech32::{primitives::decode::CheckedHrpstring, Bech32, Fe32};
389    ///
390    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
391    /// let ascii = "ar0srrr7xfkvy5l643lydnw9re59gtzz";
392    ///
393    /// let mut checked = CheckedHrpstring::new::<Bech32>(&addr).unwrap();
394    /// let witness_version = checked.remove_witness_version().unwrap();
395    /// assert_eq!(witness_version, Fe32::Q);
396    /// assert!(checked.data_part_ascii_no_checksum().iter().eq(ascii.as_bytes().iter()))
397    /// ```
398    #[inline]
399    pub fn remove_witness_version(&mut self) -> Option<Fe32> {
400        self.witness_version().map(|witver| {
401            self.ascii = &self.ascii[1..]; // Remove the witness version byte.
402            witver
403        })
404    }
405
406    /// Returns the segwit witness version if there is one.
407    ///
408    /// Attempts to convert the first character of the data part to a witness version. If this
409    /// succeeds, and it is a valid version (0..16 inclusive) we return it, otherwise `None`.
410    ///
411    /// Future calls to [`Self::data_part_ascii_no_checksum`] will still include the witness
412    /// version, use [`Self::remove_witness_version`] to remove it.
413    ///
414    /// This function makes no guarantees on the validity of the checksum.
415    ///
416    /// # Examples
417    ///
418    /// ```
419    /// use bech32::{primitives::decode::CheckedHrpstring, Bech32, Fe32};
420    ///
421    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
422    ///
423    /// let checked = CheckedHrpstring::new::<Bech32>(&addr).unwrap();
424    /// assert_eq!(checked.witness_version(), Some(Fe32::Q));
425    /// ```
426    #[inline]
427    pub fn witness_version(&self) -> Option<Fe32> {
428        let data_part = self.data_part_ascii_no_checksum();
429        if data_part.is_empty() {
430            return None;
431        }
432
433        // unwrap ok because we know we gave valid bech32 characters.
434        let witness_version = Fe32::from_char(data_part[0].into()).unwrap();
435        if witness_version.to_u8() > 16 {
436            return None;
437        }
438        Some(witness_version)
439    }
440
441    /// Returns an iterator that yields the data part of the parsed bech32 encoded string as [`Fe32`]s.
442    ///
443    /// Converts the ASCII bytes representing field elements to the respective field elements.
444    #[inline]
445    pub fn fe32_iter<I: Iterator<Item = u8>>(&self) -> AsciiToFe32Iter {
446        AsciiToFe32Iter { iter: self.ascii.iter().copied() }
447    }
448
449    /// Returns an iterator that yields the data part of the parsed bech32 encoded string.
450    ///
451    /// Converts the ASCII bytes representing field elements to the respective field elements, then
452    /// converts the stream of field elements to a stream of bytes.
453    #[inline]
454    pub fn byte_iter(&self) -> ByteIter {
455        ByteIter { iter: AsciiToFe32Iter { iter: self.ascii.iter().copied() }.fes_to_bytes() }
456    }
457
458    /// Converts this type to a [`SegwitHrpstring`] after validating the witness and HRP.
459    #[inline]
460    pub fn validate_segwit(mut self) -> Result<SegwitHrpstring<'s>, SegwitHrpstringError> {
461        if self.ascii.is_empty() {
462            return Err(SegwitHrpstringError::NoData);
463        }
464
465        if self.hrpstring_length > segwit::MAX_STRING_LENGTH {
466            return Err(SegwitHrpstringError::TooLong(self.hrpstring_length));
467        }
468
469        // Unwrap ok since check_characters checked the bech32-ness of this char.
470        let witness_version = Fe32::from_char(self.ascii[0].into()).unwrap();
471        self.ascii = &self.ascii[1..]; // Remove the witness version byte.
472
473        self.validate_segwit_padding()?;
474        self.validate_witness_program_length(witness_version)?;
475
476        Ok(SegwitHrpstring { hrp: self.hrp(), witness_version, ascii: self.ascii })
477    }
478
479    /// Validates the segwit padding rules.
480    ///
481    /// Must be called after the witness version byte is removed from the data part.
482    ///
483    /// From BIP-173:
484    /// > Re-arrange those bits into groups of 8 bits. Any incomplete group at the
485    /// > end MUST be 4 bits or less, MUST be all zeroes, and is discarded.
486    #[inline]
487    pub fn validate_segwit_padding(&self) -> Result<(), PaddingError> {
488        if self.ascii.is_empty() {
489            return Ok(()); // Empty data implies correct padding.
490        }
491
492        let fe_iter = AsciiToFe32Iter { iter: self.ascii.iter().copied() };
493        let padding_len = fe_iter.len() * 5 % 8;
494
495        if padding_len > 4 {
496            return Err(PaddingError::TooMuch)?;
497        }
498
499        let last_fe = fe_iter.last().expect("checked above");
500        let last_byte = last_fe.0;
501
502        let padding_contains_non_zero_bits = match padding_len {
503            0 => false,
504            1 => last_byte & 0b0001 > 0,
505            2 => last_byte & 0b0011 > 0,
506            3 => last_byte & 0b0111 > 0,
507            4 => last_byte & 0b1111 > 0,
508            _ => unreachable!("checked above"),
509        };
510        if padding_contains_non_zero_bits {
511            Err(PaddingError::NonZero)
512        } else {
513            Ok(())
514        }
515    }
516
517    /// Validates the segwit witness length rules.
518    ///
519    /// Must be called after the witness version byte is removed from the data part.
520    #[inline]
521    pub fn validate_witness_program_length(
522        &self,
523        witness_version: Fe32,
524    ) -> Result<(), WitnessLengthError> {
525        segwit::validate_witness_program_length(self.byte_iter().len(), witness_version)
526    }
527}
528
529/// An valid length HRP string that has been parsed, had the checksum validated, had the witness
530/// version validated, had the witness data length checked, and the had witness version and checksum
531/// removed.
532///
533/// # Examples
534///
535/// ```
536/// use bech32::primitives::decode::SegwitHrpstring;
537///
538/// // Parse a segwit V0 address.
539/// let address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
540/// let segwit = SegwitHrpstring::new(address).expect("valid segwit address");
541///
542/// // Do something with the encoded data.
543/// let _ = segwit.byte_iter();
544/// ```
545#[derive(Debug)]
546pub struct SegwitHrpstring<'s> {
547    /// The human-readable part, valid for segwit addresses.
548    hrp: Hrp,
549    /// The first byte of the parsed data part.
550    witness_version: Fe32,
551    /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters.
552    ///
553    /// The characters after the witness version and before the checksum.
554    ascii: &'s [u8],
555}
556
557impl<'s> SegwitHrpstring<'s> {
558    /// Parses an HRP string, treating the first data character as a witness version.
559    ///
560    /// The version byte does not appear in the extracted binary data, but is covered by the
561    /// checksum. It can be accessed with [`Self::witness_version`].
562    ///
563    /// NOTE: We do not enforce any restrictions on the HRP, use [`SegwitHrpstring::has_valid_hrp`]
564    /// to get strict BIP conformance (also [`Hrp::is_valid_on_mainnet`] and friends).
565    #[inline]
566    pub fn new(s: &'s str) -> Result<Self, SegwitHrpstringError> {
567        let len = s.len();
568        if len > segwit::MAX_STRING_LENGTH {
569            return Err(SegwitHrpstringError::TooLong(len));
570        }
571
572        let unchecked = UncheckedHrpstring::new(s)?;
573
574        let data_part = unchecked.data_part_ascii();
575
576        if data_part.is_empty() {
577            return Err(SegwitHrpstringError::NoData);
578        }
579
580        // Unwrap ok since check_characters (in `Self::new`) checked the bech32-ness of this char.
581        let witness_version = Fe32::from_char(data_part[0].into()).unwrap();
582        if witness_version.to_u8() > 16 {
583            return Err(SegwitHrpstringError::InvalidWitnessVersion(witness_version));
584        }
585
586        let checked: CheckedHrpstring<'s> = match witness_version {
587            VERSION_0 => unchecked.validate_and_remove_checksum::<Bech32>()?,
588            _ => unchecked.validate_and_remove_checksum::<Bech32m>()?,
589        };
590
591        checked.validate_segwit()
592    }
593
594    /// Parses an HRP string, treating the first data character as a witness version.
595    ///
596    /// ## WARNING
597    ///
598    /// You almost certainly do not want to use this function.
599    ///
600    /// It is provided for backwards comparability to parse addresses that have an non-zero witness
601    /// version because [BIP-173] explicitly allows using the bech32 checksum with any witness
602    /// version however [BIP-350] specifies all witness version > 0 now MUST use bech32m.
603    ///
604    /// [BIP-173]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
605    /// [BIP-350]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
606    #[inline]
607    pub fn new_bech32(s: &'s str) -> Result<Self, SegwitHrpstringError> {
608        let unchecked = UncheckedHrpstring::new(s)?;
609        let data_part = unchecked.data_part_ascii();
610
611        // Unwrap ok since check_characters (in `Self::new`) checked the bech32-ness of this char.
612        let witness_version = Fe32::from_char(data_part[0].into()).unwrap();
613        if witness_version.to_u8() > 16 {
614            return Err(SegwitHrpstringError::InvalidWitnessVersion(witness_version));
615        }
616
617        let checked = unchecked.validate_and_remove_checksum::<Bech32>()?;
618        checked.validate_segwit()
619    }
620
621    /// Returns `true` if the HRP is "bc" or "tb".
622    ///
623    /// BIP-173 requires that the HRP is "bc" or "tb" but software in the Bitcoin ecosystem uses
624    /// other HRPs, specifically "bcrt" for regtest addresses. We provide this function in order to
625    /// be BIP-173 compliant but their are no restrictions on the HRP of [`SegwitHrpstring`].
626    #[inline]
627    pub fn has_valid_hrp(&self) -> bool { self.hrp().is_valid_segwit() }
628
629    /// Returns the human-readable part.
630    #[inline]
631    pub fn hrp(&self) -> Hrp { self.hrp }
632
633    /// Returns the witness version.
634    #[inline]
635    pub fn witness_version(&self) -> Fe32 { self.witness_version }
636
637    /// Returns a partial slice of the data part, as ASCII bytes, everything after the witness
638    /// version and before the checksum.
639    ///
640    /// The byte values are guaranteed to be valid bech32 characters.
641    ///
642    /// # Examples
643    ///
644    /// ```
645    /// use bech32::{Bech32, primitives::decode::SegwitHrpstring};
646    ///
647    /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
648    /// let ascii = "ar0srrr7xfkvy5l643lydnw9re59gtzz";
649    ///
650    /// let segwit = SegwitHrpstring::new(&addr).unwrap();
651    /// assert!(segwit.data_part_ascii_no_witver_no_checksum().iter().eq(ascii.as_bytes().iter()))
652    /// ```
653    #[inline]
654    pub fn data_part_ascii_no_witver_no_checksum(&self) -> &'s [u8] { self.ascii }
655
656    /// Returns an iterator that yields the data part, excluding the witness version, of the parsed
657    /// bech32 encoded string.
658    ///
659    /// Converts the ASCII bytes representing field elements to the respective field elements, then
660    /// converts the stream of field elements to a stream of bytes.
661    ///
662    /// Use `self.witness_version()` to get the witness version.
663    #[inline]
664    pub fn byte_iter(&self) -> ByteIter {
665        ByteIter { iter: AsciiToFe32Iter { iter: self.ascii.iter().copied() }.fes_to_bytes() }
666    }
667}
668
669/// Checks whether a given HRP string has data part characters in the bech32 alphabet (incl.
670/// checksum characters), and that the whole string has consistent casing (hrp and data part).
671///
672/// # Returns
673///
674/// The byte-index into the string where the '1' separator occurs, or an error if it does not.
675fn check_characters(s: &str) -> Result<usize, CharError> {
676    use CharError::*;
677
678    let mut has_upper = false;
679    let mut has_lower = false;
680    let mut req_bech32 = true;
681    let mut sep_pos = None;
682    for (n, ch) in s.char_indices().rev() {
683        if ch == SEP && sep_pos.is_none() {
684            req_bech32 = false;
685            sep_pos = Some(n);
686        }
687        if req_bech32 {
688            Fe32::from_char(ch).map_err(|_| InvalidChar(ch))?;
689        }
690        if ch.is_ascii_uppercase() {
691            has_upper = true;
692        } else if ch.is_ascii_lowercase() {
693            has_lower = true;
694        }
695    }
696    if has_upper && has_lower {
697        Err(MixedCase)
698    } else if let Some(pos) = sep_pos {
699        Ok(pos)
700    } else {
701        Err(MissingSeparator)
702    }
703}
704
705/// An iterator over a parsed HRP string data as bytes.
706pub struct ByteIter<'s> {
707    iter: FesToBytes<AsciiToFe32Iter<'s>>,
708}
709
710impl<'s> Iterator for ByteIter<'s> {
711    type Item = u8;
712    #[inline]
713    fn next(&mut self) -> Option<u8> { self.iter.next() }
714    #[inline]
715    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
716}
717
718impl<'s> ExactSizeIterator for ByteIter<'s> {
719    #[inline]
720    fn len(&self) -> usize { self.iter.len() }
721}
722
723/// An iterator over a parsed HRP string data as field elements.
724pub struct Fe32Iter<'s> {
725    iter: AsciiToFe32Iter<'s>,
726}
727
728impl<'s> Iterator for Fe32Iter<'s> {
729    type Item = Fe32;
730    #[inline]
731    fn next(&mut self) -> Option<Fe32> { self.iter.next() }
732    #[inline]
733    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
734}
735
736/// Iterator adaptor that maps an iterator of valid bech32 character ASCII bytes to an
737/// iterator of field elements.
738///
739/// # Panics
740///
741/// If any `u8` in the input iterator is out of range for an [`Fe32`]. Should only be used on data
742/// that has already been checked for validity (eg, by using `check_characters`).
743pub struct AsciiToFe32Iter<'s> {
744    iter: iter::Copied<slice::Iter<'s, u8>>,
745}
746
747impl<'s> Iterator for AsciiToFe32Iter<'s> {
748    type Item = Fe32;
749    #[inline]
750    fn next(&mut self) -> Option<Fe32> { self.iter.next().map(Fe32::from_char_unchecked) }
751    #[inline]
752    fn size_hint(&self) -> (usize, Option<usize>) {
753        // Each ASCII character is an fe32 so iterators are the same size.
754        self.iter.size_hint()
755    }
756}
757
758impl<'s> ExactSizeIterator for AsciiToFe32Iter<'s> {
759    #[inline]
760    fn len(&self) -> usize { self.iter.len() }
761}
762
763/// An error while constructing a [`SegwitHrpstring`] type.
764#[derive(Debug, Clone, PartialEq, Eq)]
765#[non_exhaustive]
766pub enum SegwitHrpstringError {
767    /// Error while parsing the encoded address string.
768    Unchecked(UncheckedHrpstringError),
769    /// No data found after removing the checksum.
770    NoData,
771    /// String exceeds maximum allowed length.
772    TooLong(usize),
773    /// Invalid witness version (must be 0-16 inclusive).
774    InvalidWitnessVersion(Fe32),
775    /// Invalid padding on the witness data.
776    Padding(PaddingError),
777    /// Invalid witness length.
778    WitnessLength(WitnessLengthError),
779    /// Invalid checksum.
780    Checksum(ChecksumError),
781}
782
783#[rustfmt::skip]
784impl fmt::Display for SegwitHrpstringError {
785    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
786        use SegwitHrpstringError::*;
787
788        match *self {
789            Unchecked(ref e) => write_err!(f, "parsing unchecked hrpstring failed"; e),
790            NoData => write!(f, "no data found after removing the checksum"),
791            TooLong(len) =>
792                write!(f, "encoded length {} exceeds spec limit {} chars", len, segwit::MAX_STRING_LENGTH),
793            InvalidWitnessVersion(fe) =>
794                write!(f, "invalid segwit witness version: {} (bech32 character: '{}')", fe.to_u8(), fe),
795            Padding(ref e) => write_err!(f, "invalid padding on the witness data"; e),
796            WitnessLength(ref e) => write_err!(f, "invalid witness length"; e),
797            Checksum(ref e) => write_err!(f, "invalid checksum"; e),
798        }
799    }
800}
801
802#[cfg(feature = "std")]
803impl std::error::Error for SegwitHrpstringError {
804    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
805        use SegwitHrpstringError::*;
806
807        match *self {
808            Unchecked(ref e) => Some(e),
809            Padding(ref e) => Some(e),
810            WitnessLength(ref e) => Some(e),
811            Checksum(ref e) => Some(e),
812            NoData | TooLong(_) | InvalidWitnessVersion(_) => None,
813        }
814    }
815}
816
817impl From<UncheckedHrpstringError> for SegwitHrpstringError {
818    #[inline]
819    fn from(e: UncheckedHrpstringError) -> Self { Self::Unchecked(e) }
820}
821
822impl From<WitnessLengthError> for SegwitHrpstringError {
823    #[inline]
824    fn from(e: WitnessLengthError) -> Self { Self::WitnessLength(e) }
825}
826
827impl From<PaddingError> for SegwitHrpstringError {
828    #[inline]
829    fn from(e: PaddingError) -> Self { Self::Padding(e) }
830}
831
832impl From<ChecksumError> for SegwitHrpstringError {
833    #[inline]
834    fn from(e: ChecksumError) -> Self { Self::Checksum(e) }
835}
836
837/// An error while constructing a [`CheckedHrpstring`] type.
838#[derive(Debug, Clone, PartialEq, Eq)]
839#[non_exhaustive]
840pub enum CheckedHrpstringError {
841    /// Error while parsing the encoded address string.
842    Parse(UncheckedHrpstringError),
843    /// Invalid checksum.
844    Checksum(ChecksumError),
845}
846
847impl fmt::Display for CheckedHrpstringError {
848    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
849        use CheckedHrpstringError::*;
850
851        match *self {
852            Parse(ref e) => write_err!(f, "parse failed"; e),
853            Checksum(ref e) => write_err!(f, "invalid checksum"; e),
854        }
855    }
856}
857
858#[cfg(feature = "std")]
859impl std::error::Error for CheckedHrpstringError {
860    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
861        use CheckedHrpstringError::*;
862
863        match *self {
864            Parse(ref e) => Some(e),
865            Checksum(ref e) => Some(e),
866        }
867    }
868}
869
870impl From<UncheckedHrpstringError> for CheckedHrpstringError {
871    #[inline]
872    fn from(e: UncheckedHrpstringError) -> Self { Self::Parse(e) }
873}
874
875impl From<ChecksumError> for CheckedHrpstringError {
876    #[inline]
877    fn from(e: ChecksumError) -> Self { Self::Checksum(e) }
878}
879
880/// Errors when parsing a bech32 encoded string.
881#[derive(Debug, Clone, PartialEq, Eq)]
882#[non_exhaustive]
883pub enum UncheckedHrpstringError {
884    /// An error with the characters of the input string.
885    Char(CharError),
886    /// The human-readable part is invalid.
887    Hrp(hrp::Error),
888}
889
890impl fmt::Display for UncheckedHrpstringError {
891    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
892        use UncheckedHrpstringError::*;
893
894        match *self {
895            Char(ref e) => write_err!(f, "character error"; e),
896            Hrp(ref e) => write_err!(f, "invalid human-readable part"; e),
897        }
898    }
899}
900
901#[cfg(feature = "std")]
902impl std::error::Error for UncheckedHrpstringError {
903    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
904        use UncheckedHrpstringError::*;
905
906        match *self {
907            Char(ref e) => Some(e),
908            Hrp(ref e) => Some(e),
909        }
910    }
911}
912
913impl From<CharError> for UncheckedHrpstringError {
914    #[inline]
915    fn from(e: CharError) -> Self { Self::Char(e) }
916}
917
918impl From<hrp::Error> for UncheckedHrpstringError {
919    #[inline]
920    fn from(e: hrp::Error) -> Self { Self::Hrp(e) }
921}
922
923/// Character errors in a bech32 encoded string.
924#[derive(Debug, Clone, PartialEq, Eq)]
925#[non_exhaustive]
926pub enum CharError {
927    /// String does not contain the separator character.
928    MissingSeparator,
929    /// No characters after the separator.
930    NothingAfterSeparator,
931    /// Some part of the string contains an invalid character.
932    InvalidChar(char),
933    /// The whole string must be of one case.
934    MixedCase,
935}
936
937impl fmt::Display for CharError {
938    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
939        use CharError::*;
940
941        match *self {
942            MissingSeparator => write!(f, "missing human-readable separator, \"{}\"", SEP),
943            NothingAfterSeparator => write!(f, "invalid data - no characters after the separator"),
944            InvalidChar(n) => write!(f, "invalid character (code={})", n),
945            MixedCase => write!(f, "mixed-case strings not allowed"),
946        }
947    }
948}
949
950#[cfg(feature = "std")]
951impl std::error::Error for CharError {
952    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
953        use CharError::*;
954
955        match *self {
956            MissingSeparator | NothingAfterSeparator | InvalidChar(_) | MixedCase => None,
957        }
958    }
959}
960
961/// Errors in the checksum of a bech32 encoded string.
962#[derive(Debug, Clone, PartialEq, Eq)]
963#[non_exhaustive]
964pub enum ChecksumError {
965    /// String exceeds maximum allowed length.
966    CodeLength(CodeLengthError),
967    /// The checksum residue is not valid for the data.
968    InvalidResidue,
969    /// The checksummed string is not a valid length.
970    InvalidLength,
971}
972
973impl fmt::Display for ChecksumError {
974    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
975        use ChecksumError::*;
976
977        match *self {
978            CodeLength(ref e) => write_err!(f, "string exceeds maximum allowed length"; e),
979            InvalidResidue => write!(f, "the checksum residue is not valid for the data"),
980            InvalidLength => write!(f, "the checksummed string is not a valid length"),
981        }
982    }
983}
984
985#[cfg(feature = "std")]
986impl std::error::Error for ChecksumError {
987    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
988        use ChecksumError::*;
989
990        match *self {
991            CodeLength(ref e) => Some(e),
992            InvalidResidue | InvalidLength => None,
993        }
994    }
995}
996
997/// Encoding HRP and data into a bech32 string exceeds the checksum code length.
998#[derive(Debug, Clone, PartialEq, Eq)]
999#[non_exhaustive]
1000pub struct CodeLengthError {
1001    /// The length of the string if encoded with checksum.
1002    pub encoded_length: usize,
1003    /// The checksum specific code length.
1004    pub code_length: usize,
1005}
1006
1007impl fmt::Display for CodeLengthError {
1008    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1009        write!(
1010            f,
1011            "encoded length {} exceeds maximum (code length) {}",
1012            self.encoded_length, self.code_length
1013        )
1014    }
1015}
1016
1017#[cfg(feature = "std")]
1018impl std::error::Error for CodeLengthError {
1019    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
1020}
1021
1022/// Encoding HRP, witver, and program into an address exceeds maximum allowed.
1023#[derive(Debug, Clone, PartialEq, Eq)]
1024#[non_exhaustive]
1025pub struct SegwitCodeLengthError(pub usize);
1026
1027impl fmt::Display for SegwitCodeLengthError {
1028    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1029        write!(
1030            f,
1031            "encoded length {} exceeds maximum (code length) {}",
1032            self.0,
1033            segwit::MAX_STRING_LENGTH
1034        )
1035    }
1036}
1037
1038#[cfg(feature = "std")]
1039impl std::error::Error for SegwitCodeLengthError {
1040    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
1041}
1042
1043impl From<CodeLengthError> for SegwitCodeLengthError {
1044    fn from(e: CodeLengthError) -> Self { Self(e.encoded_length) }
1045}
1046
1047/// Error validating the padding bits on the witness data.
1048#[derive(Debug, Clone, PartialEq, Eq)]
1049#[non_exhaustive]
1050pub enum PaddingError {
1051    /// The data payload has too many bits of padding.
1052    TooMuch,
1053    /// The data payload is padded with non-zero bits.
1054    NonZero,
1055}
1056
1057impl fmt::Display for PaddingError {
1058    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1059        use PaddingError::*;
1060
1061        match *self {
1062            TooMuch => write!(f, "the data payload has too many bits of padding"),
1063            NonZero => write!(f, "the data payload is padded with non-zero bits"),
1064        }
1065    }
1066}
1067
1068#[cfg(feature = "std")]
1069impl std::error::Error for PaddingError {
1070    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1071        use PaddingError::*;
1072
1073        match *self {
1074            TooMuch | NonZero => None,
1075        }
1076    }
1077}
1078
1079#[cfg(test)]
1080mod tests {
1081    use super::*;
1082
1083    #[test]
1084    fn bip_173_invalid_parsing_fails() {
1085        use UncheckedHrpstringError::*;
1086
1087        let invalid: Vec<(&str, UncheckedHrpstringError)> = vec!(
1088            ("\u{20}1nwldj5",
1089             // TODO: Rust >= 1.59.0 use Hrp(hrp::Error::InvalidAsciiByte('\u{20}'.try_into().unwrap()))),
1090             Hrp(hrp::Error::InvalidAsciiByte(32))),
1091            ("\u{7F}1axkwrx",
1092             Hrp(hrp::Error::InvalidAsciiByte(127))),
1093            ("\u{80}1eym55h",
1094             Hrp(hrp::Error::NonAsciiChar('\u{80}'))),
1095            ("an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4",
1096             Hrp(hrp::Error::TooLong(84))),
1097            ("pzry9x0s0muk",
1098             Char(CharError::MissingSeparator)),
1099            ("1pzry9x0s0muk",
1100             Hrp(hrp::Error::Empty)),
1101            ("x1b4n0q5v",
1102             Char(CharError::InvalidChar('b'))),
1103            // "li1dgmt3" in separate test because error is a checksum error.
1104            ("de1lg7wt\u{ff}",
1105             Char(CharError::InvalidChar('\u{ff}'))),
1106            // "A1G7SGD8" in separate test because error is a checksum error.
1107            ("10a06t8",
1108             Hrp(hrp::Error::Empty)),
1109            ("1qzzfhee",
1110             Hrp(hrp::Error::Empty)),
1111        );
1112
1113        for (s, want) in invalid {
1114            let got = UncheckedHrpstring::new(s).unwrap_err();
1115            assert_eq!(got, want);
1116        }
1117    }
1118
1119    #[test]
1120    fn bip_173_invalid_parsing_fails_invalid_checksum() {
1121        use ChecksumError::*;
1122
1123        let err = UncheckedHrpstring::new("li1dgmt3")
1124            .expect("string parses correctly")
1125            .validate_checksum::<Bech32>()
1126            .unwrap_err();
1127        assert_eq!(err, InvalidLength);
1128
1129        let err = UncheckedHrpstring::new("A1G7SGD8")
1130            .expect("string parses correctly")
1131            .validate_checksum::<Bech32>()
1132            .unwrap_err();
1133        assert_eq!(err, InvalidResidue);
1134    }
1135
1136    #[test]
1137    fn bip_350_invalid_parsing_fails() {
1138        use UncheckedHrpstringError::*;
1139
1140        let invalid: Vec<(&str, UncheckedHrpstringError)> = vec!(
1141            ("\u{20}1xj0phk",
1142             // TODO: Rust >= 1.59.0 use Hrp(hrp::Error::InvalidAsciiByte('\u{20}'.try_into().unwrap()))),
1143             Hrp(hrp::Error::InvalidAsciiByte(32))),
1144            ("\u{7F}1g6xzxy",
1145             Hrp(hrp::Error::InvalidAsciiByte(127))),
1146            ("\u{80}1g6xzxy",
1147             Hrp(hrp::Error::NonAsciiChar('\u{80}'))),
1148            ("an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
1149             Hrp(hrp::Error::TooLong(84))),
1150            ("qyrz8wqd2c9m",
1151             Char(CharError::MissingSeparator)),
1152            ("1qyrz8wqd2c9m",
1153             Hrp(hrp::Error::Empty)),
1154            ("y1b0jsk6g",
1155             Char(CharError::InvalidChar('b'))),
1156            ("lt1igcx5c0",
1157             Char(CharError::InvalidChar('i'))),
1158            // "in1muywd" in separate test because error is a checksum error.
1159            ("mm1crxm3i",
1160             Char(CharError::InvalidChar('i'))),
1161            ("au1s5cgom",
1162             Char(CharError::InvalidChar('o'))),
1163            // "M1VUXWEZ" in separate test because error is a checksum error.
1164            ("16plkw9",
1165             Hrp(hrp::Error::Empty)),
1166            ("1p2gdwpf",
1167             Hrp(hrp::Error::Empty)),
1168
1169        );
1170
1171        for (s, want) in invalid {
1172            let got = UncheckedHrpstring::new(s).unwrap_err();
1173            assert_eq!(got, want);
1174        }
1175    }
1176
1177    #[test]
1178    fn bip_350_invalid_because_of_invalid_checksum() {
1179        use ChecksumError::*;
1180
1181        // Note the "bc1p2" test case is not from the bip test vectors.
1182        let invalid: Vec<&str> = vec!["in1muywd", "bc1p2"];
1183
1184        for s in invalid {
1185            let err =
1186                UncheckedHrpstring::new(s).unwrap().validate_checksum::<Bech32m>().unwrap_err();
1187            assert_eq!(err, InvalidLength);
1188        }
1189
1190        let err = UncheckedHrpstring::new("M1VUXWEZ")
1191            .unwrap()
1192            .validate_checksum::<Bech32m>()
1193            .unwrap_err();
1194        assert_eq!(err, InvalidResidue);
1195    }
1196
1197    #[test]
1198    fn check_hrp_uppercase_returns_lower() {
1199        let addr = "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4";
1200        let unchecked = UncheckedHrpstring::new(addr).expect("failed to parse address");
1201        assert_eq!(unchecked.hrp(), Hrp::parse_unchecked("bc"));
1202    }
1203
1204    #[test]
1205    #[cfg(feature = "alloc")]
1206    fn check_hrp_max_length() {
1207        let hrps =
1208            "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio";
1209
1210        let hrp = Hrp::parse_unchecked(hrps);
1211        let s = crate::encode::<Bech32>(hrp, &[]).expect("failed to encode empty buffer");
1212
1213        let unchecked = UncheckedHrpstring::new(&s).expect("failed to parse address");
1214        assert_eq!(unchecked.hrp(), hrp);
1215    }
1216
1217    #[test]
1218    fn mainnet_valid_addresses() {
1219        let addresses = vec![
1220            "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
1221            "23451QAR0SRRR7XFKVY5L643LYDNW9RE59GTZZLKULZK",
1222        ];
1223        for valid in addresses {
1224            assert!(CheckedHrpstring::new::<Bech32>(valid).is_ok())
1225        }
1226    }
1227
1228    macro_rules! check_invalid_segwit_addresses {
1229        ($($test_name:ident, $reason:literal, $address:literal);* $(;)?) => {
1230            $(
1231                #[test]
1232                fn $test_name() {
1233                    let res = SegwitHrpstring::new($address);
1234                    if res.is_ok() {
1235                        panic!("{} sting should not be valid: {}", $address, $reason);
1236                    }
1237                }
1238            )*
1239        }
1240    }
1241    check_invalid_segwit_addresses! {
1242        invalid_segwit_address_0, "missing hrp", "1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
1243        invalid_segwit_address_1, "missing data-checksum", "91111";
1244        invalid_segwit_address_2, "invalid witness version", "bc14r0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
1245        invalid_segwit_address_3, "invalid checksum length", "bc1q5mdq";
1246        invalid_segwit_address_4, "missing data", "bc1qwf5mdq";
1247        invalid_segwit_address_5, "invalid program length", "bc14r0srrr7xfkvy5l643lydnw9rewf5mdq";
1248    }
1249}