codec_multibase/
encode.rs1use base64::{encoded_len, engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
6use zeroize::Zeroizing;
7
8use crate::{Base58Error, MultibaseError, MAX_BASE58BTC_DECODED_LEN};
9
10const MULTIBASE_BASE58BTC_PREFIX: u8 = b'z';
11const MULTIBASE_BASE64URL_PREFIX: u8 = b'u';
12
13pub fn bytes_to_multibase58btc(bytes: &[u8]) -> Result<String, Base58Error> {
15 if bytes.len() > MAX_BASE58BTC_DECODED_LEN {
16 return Err(Base58Error::InputTooLarge);
17 }
18 let mut output = Zeroizing::new(Vec::with_capacity(1));
19 output.push(MULTIBASE_BASE58BTC_PREFIX);
20 bs58::encode(bytes)
21 .onto(&mut *output)
22 .map_err(|_| Base58Error::BufferTooSmall)?;
23 match String::from_utf8(core::mem::take(&mut *output)) {
24 Ok(encoded) => Ok(encoded),
25 Err(error) => {
26 let _bytes = Zeroizing::new(error.into_bytes());
27 Err(Base58Error::DecodeFailed)
28 }
29 }
30}
31
32pub fn bytes_to_multibase_base64url(bytes: &[u8]) -> Result<String, MultibaseError> {
34 let encoded_length = encoded_len(bytes.len(), false).ok_or(MultibaseError::LengthOverflow)?;
35 let output_length = encoded_length
36 .checked_add(1)
37 .ok_or(MultibaseError::LengthOverflow)?;
38 let mut output = Zeroizing::new(vec![0_u8; output_length]);
39 output[0] = MULTIBASE_BASE64URL_PREFIX;
40 let written = URL_SAFE_NO_PAD
41 .encode_slice(bytes, &mut output[1..])
42 .map_err(|_| MultibaseError::LengthOverflow)?;
43 if written != encoded_length {
44 return Err(MultibaseError::LengthOverflow);
45 }
46 match String::from_utf8(core::mem::take(&mut *output)) {
47 Ok(encoded) => Ok(encoded),
48 Err(error) => {
49 let _bytes = Zeroizing::new(error.into_bytes());
50 Err(MultibaseError::LengthOverflow)
51 }
52 }
53}