codec_multibase/
base58btc.rs1use bs58::decode::Error as Bs58DecodeError;
6use thiserror::Error;
7use zeroize::Zeroizing;
8
9pub const MAX_BASE58BTC_INPUT_LEN: usize = 8 * 1024;
15
16#[derive(Debug, Error)]
18#[non_exhaustive]
19pub enum Base58Error {
20 #[error("base58btc output buffer too small")]
22 BufferTooSmall,
23 #[error("base58btc decode failed")]
25 DecodeFailed,
26 #[error("invalid base58btc character")]
28 InvalidCharacter,
29 #[error("non-ascii base58btc character")]
31 NonAsciiCharacter,
32 #[error("base58btc input too large")]
34 InputTooLarge,
35}
36
37impl From<Bs58DecodeError> for Base58Error {
38 fn from(value: Bs58DecodeError) -> Self {
39 match value {
40 Bs58DecodeError::BufferTooSmall => Self::BufferTooSmall,
41 Bs58DecodeError::InvalidCharacter { .. } => Self::InvalidCharacter,
42 Bs58DecodeError::NonAsciiCharacter { .. } => Self::NonAsciiCharacter,
43 _ => Self::DecodeFailed,
44 }
45 }
46}
47
48pub fn base58btc_encode(bytes: &[u8]) -> Result<String, Base58Error> {
50 if bytes.len() > MAX_BASE58BTC_INPUT_LEN {
51 return Err(Base58Error::InputTooLarge);
52 }
53 let mut output = Zeroizing::new(Vec::new());
54 bs58::encode(bytes)
55 .onto(&mut *output)
56 .map_err(|_| Base58Error::BufferTooSmall)?;
57 match String::from_utf8(core::mem::take(&mut *output)) {
58 Ok(encoded) => Ok(encoded),
59 Err(error) => {
60 let _bytes = Zeroizing::new(error.into_bytes());
61 Err(Base58Error::DecodeFailed)
62 }
63 }
64}
65
66pub fn base58btc_decode(s: &str) -> Result<Vec<u8>, Base58Error> {
70 if s.len() > MAX_BASE58BTC_INPUT_LEN {
71 return Err(Base58Error::InputTooLarge);
72 }
73 bs58::decode(s).into_vec().map_err(Base58Error::from)
74}