cardano_serialization_lib/chain_crypto/
bech32.rs

1use 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        .to_string()
22}
23
24pub fn try_from_bech32_to_bytes<B: Bech32>(bech32_str: &str) -> Result<Vec<u8>> {
25    let (hrp, bech32_data) = bech32::decode(bech32_str)?;
26    if hrp != B::BECH32_HRP {
27        return Err(Error::HrpInvalid {
28            expected: B::BECH32_HRP,
29            actual: hrp,
30        });
31    }
32    Vec::<u8>::from_base32(&bech32_data).map_err(Into::into)
33}
34
35#[derive(Debug)]
36pub enum Error {
37    Bech32Malformed(Bech32Error),
38    HrpInvalid {
39        expected: &'static str,
40        actual: String,
41    },
42    DataInvalid(Box<dyn StdError + Send + Sync + 'static>),
43}
44
45impl Error {
46    pub fn data_invalid(cause: impl StdError + Send + Sync + 'static) -> Self {
47        Error::DataInvalid(Box::new(cause))
48    }
49}
50
51impl From<Bech32Error> for Error {
52    fn from(error: Bech32Error) -> Self {
53        Error::Bech32Malformed(error)
54    }
55}
56
57impl fmt::Display for Error {
58    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
59        match self {
60            Error::Bech32Malformed(_) => write!(f, "Failed to parse bech32, invalid data format"),
61            Error::HrpInvalid { expected, actual } => write!(
62                f,
63                "Parsed bech32 has invalid HRP prefix '{}', expected '{}'",
64                actual, expected
65            ),
66            Error::DataInvalid(_) => write!(f, "Failed to parse data decoded from bech32"),
67        }
68    }
69}
70
71impl StdError for Error {
72    fn source(&self) -> Option<&(dyn StdError + 'static)> {
73        match self {
74            Error::Bech32Malformed(cause) => Some(cause),
75            Error::DataInvalid(cause) => Some(&**cause),
76            _ => None,
77        }
78    }
79}