af_sui_types/
encoding.rs

1//! Encoding types used by Sui.
2//!
3//! This module is mostly to avoid importing [`fastcrypto`](https://github.com/MystenLabs/fastcrypto)
4
5use base64::Engine;
6use base64::engine::GeneralPurpose;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde_with::base64::Base64;
9use serde_with::{DeserializeAs, SerializeAs, formats};
10use sui_sdk_types::bcs::{FromBcs, ToBcs};
11
12/// Default encoder for Base64 data.
13pub(crate) const BASE64_DEFAULT_ENGINE: GeneralPurpose = GeneralPurpose::new(
14    &base64::alphabet::STANDARD,
15    base64::engine::general_purpose::PAD,
16);
17
18/// Convenience method for decoding base64 bytes the way Sui expects.
19pub fn decode_base64_default(value: impl AsRef<[u8]>) -> Result<Vec<u8>, base64::DecodeError> {
20    BASE64_DEFAULT_ENGINE.decode(value)
21}
22
23/// Convenience method for encoding bytes to base64 the way Sui expects.
24pub fn encode_base64_default(value: impl AsRef<[u8]>) -> String {
25    BASE64_DEFAULT_ENGINE.encode(value)
26}
27
28// =============================================================================
29//  Base64Bcs
30// =============================================================================
31
32/// Serialize values with base64-encoded BCS.
33///
34/// The type serializes a value as a base64 string of its BCS encoding.
35/// It works on any type compatible with [`bcs`] for (de)serialization.
36pub struct Base64Bcs<Alphabet = serde_with::base64::Standard, Padding = formats::Padded>(
37    std::marker::PhantomData<(Alphabet, Padding)>,
38)
39where
40    Alphabet: serde_with::base64::Alphabet,
41    Padding: formats::Format;
42
43impl<'de, T, Alphabet, Padding> DeserializeAs<'de, T> for Base64Bcs<Alphabet, Padding>
44where
45    Alphabet: serde_with::base64::Alphabet,
46    Padding: formats::Format,
47    T: for<'a> Deserialize<'a>,
48{
49    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
50    where
51        D: Deserializer<'de>,
52    {
53        let bytes: Vec<u8> = Base64::<Alphabet, Padding>::deserialize_as(deserializer)?;
54        FromBcs::from_bcs(&bytes).map_err(serde::de::Error::custom)
55    }
56}
57
58impl<T, Alphabet> SerializeAs<T> for Base64Bcs<Alphabet, formats::Padded>
59where
60    Alphabet: serde_with::base64::Alphabet,
61    T: Serialize,
62{
63    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
64    where
65        S: Serializer,
66    {
67        let bytes = source.to_bcs().map_err(serde::ser::Error::custom)?;
68        Base64::<Alphabet, formats::Padded>::serialize_as(&bytes, serializer)
69    }
70}
71
72impl<T, Alphabet> SerializeAs<T> for Base64Bcs<Alphabet, formats::Unpadded>
73where
74    Alphabet: serde_with::base64::Alphabet,
75    T: Serialize,
76{
77    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
78    where
79        S: Serializer,
80    {
81        let bytes = source.to_bcs().map_err(serde::ser::Error::custom)?;
82        Base64::<Alphabet, formats::Unpadded>::serialize_as(&bytes, serializer)
83    }
84}
85
86// =============================================================================
87//  Base58
88// =============================================================================
89
90/// Base58 encoding format. Can be used with [`serde_with::serde_as`].
91pub struct Base58;
92
93impl Base58 {
94    pub fn decode(data: impl AsRef<[u8]>) -> Result<Vec<u8>, bs58::decode::Error> {
95        bs58::decode(data).into_vec()
96    }
97
98    pub fn encode(data: impl AsRef<[u8]>) -> String {
99        bs58::encode(data).into_string()
100    }
101}
102
103impl<'de, T> DeserializeAs<'de, T> for Base58
104where
105    T: TryFrom<Vec<u8>>,
106    T::Error: std::fmt::Debug,
107{
108    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
109    where
110        D: Deserializer<'de>,
111    {
112        let s = String::deserialize(deserializer)?;
113        let value = Self::decode(&s).map_err(serde::de::Error::custom)?;
114        let length = value.len();
115        value
116            .try_into()
117            .map_err(|error| serde::de::Error::custom(BytesConversionError { length, error }))
118    }
119}
120
121#[derive(thiserror::Error, Debug)]
122#[error("Converting from a Byte Vector of length {length}: {error:?}")]
123pub struct BytesConversionError<E> {
124    pub length: usize,
125    pub error: E,
126}
127
128impl<T> SerializeAs<T> for Base58
129where
130    T: AsRef<[u8]>,
131{
132    fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
133    where
134        S: Serializer,
135    {
136        Self::encode(value).serialize(serializer)
137    }
138}