1#![allow(unknown_lints)]
46#![allow(bare_trait_objects)]
47#![deny(missing_docs)]
48#![deny(non_upper_case_globals)]
49#![deny(non_camel_case_types)]
50#![deny(non_snake_case)]
51#![deny(unused_mut)]
52#![cfg_attr(feature = "strict", deny(warnings))]
53#![cfg_attr(not(feature = "std"), no_std)]
54
55use core::fmt;
56
57#[cfg(feature = "std")]
58use std::borrow::Cow;
59
60#[cfg(not(feature = "std"))]
61extern crate alloc;
62#[cfg(not(feature = "std"))]
63use alloc::{borrow::Cow, string::String, vec::Vec};
64
65#[allow(unused_imports, deprecated)]
67#[cfg(feature = "std")]
68use std::ascii::AsciiExt;
69
70#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, PartialOrd, Ord, Hash)]
72#[allow(non_camel_case_types)]
73pub struct u5(u8);
74
75impl u5 {
76 pub fn try_from_u8(value: u8) -> Result<u5, Error> {
78 if value > 31 {
79 Err(Error::InvalidData(value))
80 } else {
81 Ok(u5(value))
82 }
83 }
84
85 pub fn to_u8(self) -> u8 {
87 self.0
88 }
89
90 pub fn to_char(self) -> char {
92 CHARSET[self.to_u8() as usize]
93 }
94}
95
96impl Into<u8> for u5 {
97 fn into(self) -> u8 {
98 self.0
99 }
100}
101
102impl AsRef<u8> for u5 {
103 fn as_ref(&self) -> &u8 {
104 &self.0
105 }
106}
107
108pub trait WriteBase32 {
110 type Err: fmt::Debug;
112
113 fn write(&mut self, data: &[u5]) -> Result<(), Self::Err> {
115 for b in data {
116 self.write_u5(*b)?;
117 }
118 Ok(())
119 }
120
121 fn write_u5(&mut self, data: u5) -> Result<(), Self::Err>;
123}
124
125pub struct Bech32Writer<'a> {
128 formatter: &'a mut fmt::Write,
129 chk: u32,
130}
131
132impl<'a> Bech32Writer<'a> {
133 pub fn new(hrp: &str, fmt: &'a mut fmt::Write) -> Result<Bech32Writer<'a>, fmt::Error> {
138 let mut writer = Bech32Writer {
139 formatter: fmt,
140 chk: 1,
141 };
142
143 writer.formatter.write_str(hrp)?;
144 writer.formatter.write_char(SEP)?;
145
146 for b in hrp.bytes() {
148 writer.polymod_step(u5(b >> 5));
149 }
150 writer.polymod_step(u5(0));
151 for b in hrp.bytes() {
152 writer.polymod_step(u5(b & 0x1f));
153 }
154
155 Ok(writer)
156 }
157
158 fn polymod_step(&mut self, v: u5) {
159 let b = (self.chk >> 25) as u8;
160 self.chk = (self.chk & 0x01ff_ffff) << 5 ^ (u32::from(*v.as_ref()));
161
162 for (i, item) in GEN.iter().enumerate() {
163 if (b >> i) & 1 == 1 {
164 self.chk ^= item;
165 }
166 }
167 }
168
169 pub fn finalize(mut self) -> fmt::Result {
171 self.inner_finalize()?;
172 #[cfg(feature = "std")]
173 std::mem::forget(self);
174 Ok(())
175 }
176
177 fn inner_finalize(&mut self) -> fmt::Result {
178 for _ in 0..6 {
180 self.polymod_step(u5(0))
181 }
182
183 let plm: u32 = self.chk ^ 1;
184
185 for p in 0..6 {
186 self.formatter
187 .write_char(u5(((plm >> (5 * (5 - p))) & 0x1f) as u8).to_char())?;
188 }
189
190 Ok(())
191 }
192}
193impl<'a> WriteBase32 for Bech32Writer<'a> {
194 type Err = fmt::Error;
195
196 fn write_u5(&mut self, data: u5) -> fmt::Result {
198 self.polymod_step(data);
199 self.formatter.write_char(data.to_char())
200 }
201}
202
203impl<'a> Drop for Bech32Writer<'a> {
204 fn drop(&mut self) {
205 self.inner_finalize()
206 .expect("Unhandled error writing the checksum on drop.")
207 }
208}
209
210pub trait FromBase32: Sized {
213 type Err;
215
216 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err>;
218}
219
220impl WriteBase32 for Vec<u5> {
221 type Err = ();
222
223 fn write(&mut self, data: &[u5]) -> Result<(), Self::Err> {
224 self.extend_from_slice(data);
225 Ok(())
226 }
227
228 fn write_u5(&mut self, data: u5) -> Result<(), Self::Err> {
229 self.push(data);
230 Ok(())
231 }
232}
233
234impl FromBase32 for Vec<u8> {
235 type Err = Error;
236
237 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
240 convert_bits(b32, 5, 8, false)
241 }
242}
243
244pub trait ToBase32 {
246 fn to_base32(&self) -> Vec<u5> {
248 let mut vec = Vec::new();
249 self.write_base32(&mut vec).unwrap();
250 vec
251 }
252
253 fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err>;
256}
257
258pub trait Base32Len: ToBase32 {
260 fn base32_len(&self) -> usize;
262}
263
264impl<T: AsRef<[u8]>> ToBase32 for T {
265 fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
266 let mut buffer_bits = 0u32;
268 let mut buffer: u8 = 0;
272
273 for &b in self.as_ref() {
274 if buffer_bits >= 5 {
278 writer.write_u5(u5((buffer & 0b1111_1000) >> 3))?;
279 buffer <<= 5;
280 buffer_bits -= 5;
281 }
282
283 let from_buffer = buffer >> 3;
286 let from_byte = b >> (3 + buffer_bits); writer.write_u5(u5(from_buffer | from_byte))?;
289 buffer = b << (5 - buffer_bits);
290 buffer_bits += 3;
291 }
292
293 if buffer_bits >= 5 {
295 writer.write_u5(u5((buffer & 0b1111_1000) >> 3))?;
296 buffer <<= 5;
297 buffer_bits -= 5;
298 }
299
300 if buffer_bits != 0 {
301 writer.write_u5(u5(buffer >> 3))?;
302 }
303
304 Ok(())
305 }
306}
307
308impl<T: AsRef<[u8]>> Base32Len for T {
309 fn base32_len(&self) -> usize {
310 let bits = self.as_ref().len() * 8;
311 if bits % 5 == 0 {
312 bits / 5
313 } else {
314 bits / 5 + 1
315 }
316 }
317}
318
319pub trait CheckBase32<T: AsRef<[u5]>> {
322 type Err;
324
325 fn check_base32(self) -> Result<T, Self::Err>;
327}
328
329impl<'f, T: AsRef<[u8]>> CheckBase32<Vec<u5>> for T {
330 type Err = Error;
331
332 fn check_base32(self) -> Result<Vec<u5>, Self::Err> {
333 self.as_ref()
334 .iter()
335 .map(|x| u5::try_from_u8(*x))
336 .collect::<Result<Vec<u5>, Error>>()
337 }
338}
339
340#[derive(Clone, Copy, PartialEq, Eq)]
341enum Case {
342 Upper,
343 Lower,
344 None,
345}
346
347fn check_hrp(hrp: &str) -> Result<Case, Error> {
354 if hrp.is_empty() || hrp.len() > 83 {
355 return Err(Error::InvalidLength);
356 }
357
358 let mut has_lower: bool = false;
359 let mut has_upper: bool = false;
360 for b in hrp.bytes() {
361 if b < 33 || b > 126 {
363 return Err(Error::InvalidChar(b as char));
364 }
365
366 if b >= b'a' && b <= b'z' {
367 has_lower = true;
368 } else if b >= b'A' && b <= b'Z' {
369 has_upper = true;
370 };
371
372 if has_lower && has_upper {
373 return Err(Error::MixedCase);
374 }
375 }
376
377 Ok(match (has_upper, has_lower) {
378 (true, false) => Case::Upper,
379 (false, true) => Case::Lower,
380 (false, false) => Case::None,
381 (true, true) => unreachable!(),
382 })
383}
384
385pub fn encode_to_fmt<T: AsRef<[u5]>>(
393 fmt: &mut fmt::Write,
394 hrp: &str,
395 data: T,
396) -> Result<fmt::Result, Error> {
397 let hrp_lower = match check_hrp(&hrp)? {
398 Case::Upper => Cow::Owned(hrp.to_lowercase()),
399 Case::Lower | Case::None => Cow::Borrowed(hrp),
400 };
401
402 match Bech32Writer::new(&hrp_lower, fmt) {
403 Ok(mut writer) => {
404 Ok(writer.write(data.as_ref()).and_then(|_| {
405 writer.finalize()
407 }))
408 }
409 Err(e) => Ok(Err(e)),
410 }
411}
412
413pub fn encode<T: AsRef<[u5]>>(hrp: &str, data: T) -> Result<String, Error> {
420 let mut buf = String::new();
421 encode_to_fmt(&mut buf, hrp, data)?.unwrap();
422 Ok(buf)
423}
424
425pub fn decode(s: &str) -> Result<(String, Vec<u5>), Error> {
429 if s.len() < 8 {
431 return Err(Error::InvalidLength);
432 }
433
434 let (raw_hrp, raw_data) = match s.rfind(SEP) {
436 None => return Err(Error::MissingSeparator),
437 Some(sep) => {
438 let (hrp, data) = s.split_at(sep);
439 (hrp, &data[1..])
440 }
441 };
442 if raw_data.len() < 6 {
443 return Err(Error::InvalidLength);
444 }
445
446 let mut case = check_hrp(&raw_hrp)?;
447 let hrp_lower = match case {
448 Case::Upper => raw_hrp.to_lowercase(),
449 Case::Lower | Case::None => String::from(raw_hrp),
451 };
452
453 let mut data = raw_data
455 .chars()
456 .map(|c| {
457 if !c.is_ascii() {
461 return Err(Error::InvalidChar(c));
462 }
463
464 if c.is_lowercase() {
465 match case {
466 Case::Upper => return Err(Error::MixedCase),
467 Case::None => case = Case::Lower,
468 Case::Lower => {}
469 }
470 } else if c.is_uppercase() {
471 match case {
472 Case::Lower => return Err(Error::MixedCase),
473 Case::None => case = Case::Upper,
474 Case::Upper => {}
475 }
476 }
477
478 let num_value = CHARSET_REV[c as usize];
480
481 if num_value > 31 || num_value < 0 {
482 return Err(Error::InvalidChar(c));
483 }
484
485 Ok(u5::try_from_u8(num_value as u8).expect("range checked above, num_value <= 31"))
486 })
487 .collect::<Result<Vec<u5>, Error>>()?;
488
489 if !verify_checksum(&hrp_lower.as_bytes(), &data) {
491 return Err(Error::InvalidChecksum);
492 }
493
494 let dbl: usize = data.len();
496 data.truncate(dbl - 6);
497
498 Ok((hrp_lower, data))
499}
500
501fn verify_checksum(hrp: &[u8], data: &[u5]) -> bool {
502 let mut exp = hrp_expand(hrp);
503 exp.extend_from_slice(data);
504 polymod(&exp) == 1u32
505}
506
507fn hrp_expand(hrp: &[u8]) -> Vec<u5> {
508 let mut v: Vec<u5> = Vec::new();
509 for b in hrp {
510 v.push(u5::try_from_u8(*b >> 5).expect("can't be out of range, max. 7"));
511 }
512 v.push(u5::try_from_u8(0).unwrap());
513 for b in hrp {
514 v.push(u5::try_from_u8(*b & 0x1f).expect("can't be out of range, max. 31"));
515 }
516 v
517}
518
519fn polymod(values: &[u5]) -> u32 {
520 let mut chk: u32 = 1;
521 let mut b: u8;
522 for v in values {
523 b = (chk >> 25) as u8;
524 chk = (chk & 0x01ff_ffff) << 5 ^ (u32::from(*v.as_ref()));
525
526 for (i, item) in GEN.iter().enumerate() {
527 if (b >> i) & 1 == 1 {
528 chk ^= item;
529 }
530 }
531 }
532 chk
533}
534
535const SEP: char = '1';
537
538const CHARSET: [char; 32] = [
540 'q', 'p', 'z', 'r', 'y', '9', 'x', '8', 'g', 'f', '2', 't', 'v', 'd', 'w', '0', 's', '3', 'j', 'n', '5', '4', 'k', 'h', 'c', 'e', '6', 'm', 'u', 'a', '7', 'l', ];
545
546const CHARSET_REV: [i8; 128] = [
548 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
549 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
550 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23,
551 -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, -1, 29,
552 -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1,
553 -1, -1, -1, -1,
554];
555
556const GEN: [u32; 5] = [
558 0x3b6a_57b2,
559 0x2650_8e6d,
560 0x1ea1_19fa,
561 0x3d42_33dd,
562 0x2a14_62b3,
563];
564
565#[derive(Copy, Clone, PartialEq, Debug)]
567pub enum Error {
568 MissingSeparator,
570 InvalidChecksum,
572 InvalidLength,
574 InvalidChar(char),
576 InvalidData(u8),
578 InvalidPadding,
580 MixedCase,
582}
583
584impl fmt::Display for Error {
585 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
586 match *self {
587 Error::MissingSeparator => write!(f, "missing human-readable separator, \"{}\"", SEP),
588 Error::InvalidChecksum => write!(f, "invalid checksum"),
589 Error::InvalidLength => write!(f, "invalid length"),
590 Error::InvalidChar(n) => write!(f, "invalid character (code={})", n),
591 Error::InvalidData(n) => write!(f, "invalid data point ({})", n),
592 Error::InvalidPadding => write!(f, "invalid padding"),
593 Error::MixedCase => write!(f, "mixed-case strings not allowed"),
594 }
595 }
596}
597
598#[cfg(feature = "std")]
599impl std::error::Error for Error {
600 fn description(&self) -> &str {
601 match *self {
602 Error::MissingSeparator => "missing human-readable separator",
603 Error::InvalidChecksum => "invalid checksum",
604 Error::InvalidLength => "invalid length",
605 Error::InvalidChar(_) => "invalid character",
606 Error::InvalidData(_) => "invalid data point",
607 Error::InvalidPadding => "invalid padding",
608 Error::MixedCase => "mixed-case strings not allowed",
609 }
610 }
611}
612
613pub fn convert_bits<T>(data: &[T], from: u32, to: u32, pad: bool) -> Result<Vec<u8>, Error>
631where
632 T: Into<u8> + Copy,
633{
634 if from > 8 || to > 8 || from == 0 || to == 0 {
635 panic!("convert_bits `from` and `to` parameters 0 or greater than 8");
636 }
637 let mut acc: u32 = 0;
638 let mut bits: u32 = 0;
639 let mut ret: Vec<u8> = Vec::new();
640 let maxv: u32 = (1 << to) - 1;
641 for value in data {
642 let v: u32 = u32::from(Into::<u8>::into(*value));
643 if (v >> from) != 0 {
644 return Err(Error::InvalidData(v as u8));
646 }
647 acc = (acc << from) | v;
648 bits += from;
649 while bits >= to {
650 bits -= to;
651 ret.push(((acc >> bits) & maxv) as u8);
652 }
653 }
654 if pad {
655 if bits > 0 {
656 ret.push(((acc << (to - bits)) & maxv) as u8);
657 }
658 } else if bits >= from || ((acc << (to - bits)) & maxv) != 0 {
659 return Err(Error::InvalidPadding);
660 }
661 Ok(ret)
662}
663
664#[cfg(test)]
665mod tests {
666 use super::*;
667
668 #[test]
669 fn getters() {
670 let decoded = decode("BC1SW50QA3JX3S").unwrap();
671 let data = [16, 14, 20, 15, 0].check_base32().unwrap();
672 assert_eq!(&decoded.0, "bc");
673 assert_eq!(decoded.1, data.as_slice());
674 }
675
676 #[test]
677 fn valid_checksum() {
678 let strings: Vec<&str> = vec!(
679 "A12UEL5L",
680 "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
681 "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
682 "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
683 "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
684 );
685 for s in strings {
686 let decode_result = decode(s);
687 if !decode_result.is_ok() {
688 panic!(
689 "Did not decode: {:?} Reason: {:?}",
690 s,
691 decode_result.unwrap_err()
692 );
693 }
694 assert!(decode_result.is_ok());
695 let decoded = decode_result.unwrap();
696 let encode_result = encode(&decoded.0, decoded.1).unwrap();
697 assert_eq!(s.to_lowercase(), encode_result.to_lowercase());
698 }
699 }
700
701 #[test]
702 fn invalid_strings() {
703 let pairs: Vec<(&str, Error)> = vec!(
704 (" 1nwldj5",
705 Error::InvalidChar(' ')),
706 ("abc1\u{2192}axkwrx",
707 Error::InvalidChar('\u{2192}')),
708 ("an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
709 Error::InvalidLength),
710 ("pzry9x0s0muk",
711 Error::MissingSeparator),
712 ("1pzry9x0s0muk",
713 Error::InvalidLength),
714 ("x1b4n0q5v",
715 Error::InvalidChar('b')),
716 ("ABC1DEFGOH",
717 Error::InvalidChar('O')),
718 ("li1dgmt3",
719 Error::InvalidLength),
720 ("de1lg7wt\u{ff}",
721 Error::InvalidChar('\u{ff}')),
722 );
723 for p in pairs {
724 let (s, expected_error) = p;
725 let dec_result = decode(s);
726 if dec_result.is_ok() {
727 println!("{:?}", dec_result.unwrap());
728 panic!("Should be invalid: {:?}", s);
729 }
730 assert_eq!(
731 dec_result.unwrap_err(),
732 expected_error,
733 "testing input '{}'",
734 s
735 );
736 }
737 }
738
739 #[test]
740 fn valid_conversion() {
741 let tests: Vec<(Vec<u8>, u32, u32, bool, Vec<u8>)> = vec![
743 (vec![0x01], 1, 1, true, vec![0x01]),
744 (vec![0x01, 0x01], 1, 1, true, vec![0x01, 0x01]),
745 (vec![0x01], 8, 8, true, vec![0x01]),
746 (vec![0x01], 8, 4, true, vec![0x00, 0x01]),
747 (vec![0x01], 8, 2, true, vec![0x00, 0x00, 0x00, 0x01]),
748 (
749 vec![0x01],
750 8,
751 1,
752 true,
753 vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
754 ),
755 (vec![0xff], 8, 5, true, vec![0x1f, 0x1c]),
756 (vec![0x1f, 0x1c], 5, 8, false, vec![0xff]),
757 ];
758 for t in tests {
759 let (data, from_bits, to_bits, pad, expected_result) = t;
760 let result = convert_bits(&data, from_bits, to_bits, pad);
761 assert!(result.is_ok());
762 assert_eq!(result.unwrap(), expected_result);
763 }
764 }
765
766 #[test]
767 fn invalid_conversion() {
768 let tests: Vec<(Vec<u8>, u32, u32, bool, Error)> = vec![
770 (vec![0xff], 8, 5, false, Error::InvalidPadding),
771 (vec![0x02], 1, 1, true, Error::InvalidData(0x02)),
772 ];
773 for t in tests {
774 let (data, from_bits, to_bits, pad, expected_error) = t;
775 let result = convert_bits(&data, from_bits, to_bits, pad);
776 assert!(result.is_err());
777 assert_eq!(result.unwrap_err(), expected_error);
778 }
779 }
780
781 #[test]
782 fn convert_bits_invalid_bit_size() {
783 use std::panic::{catch_unwind, set_hook, take_hook};
784
785 let invalid = &[(0, 8), (5, 0), (9, 5), (8, 10), (0, 16)];
786
787 for &(from, to) in invalid {
788 set_hook(Box::new(|_| {}));
789 let result = catch_unwind(|| {
790 let _ = convert_bits(&[0], from, to, true);
791 });
792 let _ = take_hook();
793 assert!(result.is_err());
794 }
795 }
796
797 #[test]
798 fn check_base32() {
799 assert!([0u8, 1, 2, 30, 31].check_base32().is_ok());
800 assert!([0u8, 1, 2, 30, 31, 32].check_base32().is_err());
801 assert!([0u8, 1, 2, 30, 31, 255].check_base32().is_err());
802
803 assert!([1u8, 2, 3, 4].check_base32().is_ok());
804 assert_eq!(
805 [30u8, 31, 35, 20].check_base32(),
806 Err(Error::InvalidData(35))
807 );
808 }
809
810 #[test]
811 fn test_encode() {
812 assert_eq!(
813 encode("", vec![1u8, 2, 3, 4].check_base32().unwrap()),
814 Err(Error::InvalidLength)
815 );
816 }
817
818 #[test]
819 fn from_base32() {
820 use FromBase32;
821 assert_eq!(
822 Vec::from_base32(&[0x1f, 0x1c].check_base32().unwrap()),
823 Ok(vec![0xff])
824 );
825 assert_eq!(
826 Vec::from_base32(&[0x1f, 0x1f].check_base32().unwrap()),
827 Err(Error::InvalidPadding)
828 );
829 }
830
831 #[test]
832 fn to_base32() {
833 use ToBase32;
834 assert_eq!([0xffu8].to_base32(), [0x1f, 0x1c].check_base32().unwrap());
835 }
836
837 #[test]
838 fn reverse_charset() {
839 use CHARSET_REV;
840
841 fn get_char_value(c: char) -> i8 {
842 let charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
843 match charset.find(c.to_ascii_lowercase()) {
844 Some(x) => x as i8,
845 None => -1,
846 }
847 }
848
849 let expected_rev_charset = (0u8..128)
850 .map(|i| get_char_value(i as char))
851 .collect::<Vec<_>>();
852
853 assert_eq!(&(CHARSET_REV[..]), expected_rev_charset.as_slice());
854 }
855
856 #[test]
857 fn writer() {
858 let hrp = "lnbc";
859 let data = "Hello World!".as_bytes().to_base32();
860
861 let mut written_str = String::new();
862 {
863 let mut writer = Bech32Writer::new(hrp, &mut written_str).unwrap();
864 writer.write(&data).unwrap();
865 writer.finalize().unwrap();
866 }
867
868 let encoded_str = encode(hrp, data).unwrap();
869
870 assert_eq!(encoded_str, written_str);
871 }
872
873 #[test]
874 fn write_on_drop() {
875 let hrp = "lntb";
876 let data = "Hello World!".as_bytes().to_base32();
877
878 let mut written_str = String::new();
879 {
880 let mut writer = Bech32Writer::new(hrp, &mut written_str).unwrap();
881 writer.write(&data).unwrap();
882 }
883
884 let encoded_str = encode(hrp, data).unwrap();
885
886 assert_eq!(encoded_str, written_str);
887 }
888
889 #[test]
890 fn test_hrp_case() {
891 use ToBase32;
893 let encoded_str = encode("HRP", [0x00, 0x00].to_base32()).unwrap();
894
895 assert_eq!(encoded_str, "hrp1qqqq40atq3");
896 }
897}