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}