cml_crypto/chain_crypto/
bech32.rs1use bech32::{Error as Bech32Error, FromBase32, ToBase32};
2use std::error::Error as StdError;
3use std::fmt;
4use std::result::Result as StdResult;
5
6pub type Result<T> = StdResult<T, Error>;
7
8pub trait Bech32 {
9 const BECH32_HRP: &'static str;
10
11 fn try_from_bech32_str(bech32_str: &str) -> Result<Self>
12 where
13 Self: Sized;
14
15 fn to_bech32_str(&self) -> String;
16}
17
18pub fn to_bech32_from_bytes<B: Bech32>(bytes: &[u8]) -> String {
19 bech32::encode(B::BECH32_HRP, bytes.to_base32())
20 .unwrap_or_else(|e| panic!("Failed to build bech32: {}", e))
21}
22
23pub fn try_from_bech32_to_bytes<B: Bech32>(bech32_str: &str) -> Result<Vec<u8>> {
24 let (hrp, bech32_data) = bech32::decode(bech32_str)?;
25 if hrp != B::BECH32_HRP {
26 return Err(Error::HrpInvalid {
27 expected: B::BECH32_HRP,
28 actual: hrp,
29 });
30 }
31 Vec::<u8>::from_base32(&bech32_data).map_err(Into::into)
32}
33
34#[derive(Debug)]
35pub enum Error {
36 Bech32Malformed(Bech32Error),
37 HrpInvalid {
38 expected: &'static str,
39 actual: String,
40 },
41 DataInvalid(Box<dyn StdError + Send + Sync + 'static>),
42}
43
44impl Error {
45 pub fn data_invalid(cause: impl StdError + Send + Sync + 'static) -> Self {
46 Error::DataInvalid(Box::new(cause))
47 }
48}
49
50impl From<Bech32Error> for Error {
51 fn from(error: Bech32Error) -> Self {
52 Error::Bech32Malformed(error)
53 }
54}
55
56impl fmt::Display for Error {
57 fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
58 match self {
59 Error::Bech32Malformed(_) => write!(f, "Failed to parse bech32, invalid data format"),
60 Error::HrpInvalid { expected, actual } => write!(
61 f,
62 "Parsed bech32 has invalid HRP prefix '{actual}', expected '{expected}'"
63 ),
64 Error::DataInvalid(_) => write!(f, "Failed to parse data decoded from bech32"),
65 }
66 }
67}
68
69impl StdError for Error {
70 fn source(&self) -> Option<&(dyn StdError + 'static)> {
71 match self {
72 Error::Bech32Malformed(cause) => Some(cause),
73 Error::DataInvalid(cause) => Some(&**cause),
74 _ => None,
75 }
76 }
77}