cardano_serialization_lib/chain_crypto/
bech32.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use bech32::{Error as Bech32Error, FromBase32, ToBase32};
use std::error::Error as StdError;
use std::fmt;
use std::result::Result as StdResult;

pub type Result<T> = StdResult<T, Error>;

pub trait Bech32 {
    const BECH32_HRP: &'static str;

    fn try_from_bech32_str(bech32_str: &str) -> Result<Self>
    where
        Self: Sized;

    fn to_bech32_str(&self) -> String;
}

pub fn to_bech32_from_bytes<B: Bech32>(bytes: &[u8]) -> String {
    bech32::encode(B::BECH32_HRP, bytes.to_base32())
        .unwrap_or_else(|e| panic!("Failed to build bech32: {}", e))
        .to_string()
}

pub fn try_from_bech32_to_bytes<B: Bech32>(bech32_str: &str) -> Result<Vec<u8>> {
    let (hrp, bech32_data) = bech32::decode(bech32_str)?;
    if hrp != B::BECH32_HRP {
        return Err(Error::HrpInvalid {
            expected: B::BECH32_HRP,
            actual: hrp,
        });
    }
    Vec::<u8>::from_base32(&bech32_data).map_err(Into::into)
}

#[derive(Debug)]
pub enum Error {
    Bech32Malformed(Bech32Error),
    HrpInvalid {
        expected: &'static str,
        actual: String,
    },
    DataInvalid(Box<dyn StdError + Send + Sync + 'static>),
}

impl Error {
    pub fn data_invalid(cause: impl StdError + Send + Sync + 'static) -> Self {
        Error::DataInvalid(Box::new(cause))
    }
}

impl From<Bech32Error> for Error {
    fn from(error: Bech32Error) -> Self {
        Error::Bech32Malformed(error)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        match self {
            Error::Bech32Malformed(_) => write!(f, "Failed to parse bech32, invalid data format"),
            Error::HrpInvalid { expected, actual } => write!(
                f,
                "Parsed bech32 has invalid HRP prefix '{}', expected '{}'",
                actual, expected
            ),
            Error::DataInvalid(_) => write!(f, "Failed to parse data decoded from bech32"),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Bech32Malformed(cause) => Some(cause),
            Error::DataInvalid(cause) => Some(&**cause),
            _ => None,
        }
    }
}