Skip to main content

fiber_types/
serde_utils.rs

1//! Serde utilities for hex and base58 serialization of types used in the Fiber Network.
2
3use molecule::prelude::Entity;
4use musig2::{
5    BinaryEncoding, CompactSignature, PartialSignature, PubNonce, SCHNORR_SIGNATURE_SIZE,
6};
7use serde::{de::Error, Deserialize, Deserializer, Serializer};
8use serde_with::{serde_conv, DeserializeAs, SerializeAs};
9
10pub fn from_hex<'de, D, E>(deserializer: D) -> Result<E, D::Error>
11where
12    D: Deserializer<'de>,
13    E: TryFrom<Vec<u8>>,
14    E::Error: core::fmt::Debug,
15{
16    String::deserialize(deserializer)
17        .and_then(|string| {
18            // Accept both "0x" prefixed and non-prefixed hex strings for backward compatibility
19            // with secp256k1::PublicKey's serde format which doesn't use "0x" prefix
20            let hex_str = string
21                .strip_prefix("0x")
22                .or_else(|| string.strip_prefix("0X"))
23                .unwrap_or(&string);
24            hex::decode(hex_str).map_err(|err| {
25                Error::custom(format!(
26                    "failed to decode hex string {}: {:?}",
27                    &string, err
28                ))
29            })
30        })
31        .and_then(|vec| {
32            vec.try_into().map_err(|err| {
33                Error::custom(format!("failed to convert vector into type: {:?}", err))
34            })
35        })
36}
37
38pub fn to_hex<E, S>(e: E, serializer: S) -> Result<S::Ok, S::Error>
39where
40    E: AsRef<[u8]>,
41    S: Serializer,
42{
43    to_hex_with_prefix(e, serializer, true)
44}
45
46fn to_hex_with_prefix<E, S>(e: E, serializer: S, with_prefix: bool) -> Result<S::Ok, S::Error>
47where
48    E: AsRef<[u8]>,
49    S: Serializer,
50{
51    let hex_str = hex::encode(e.as_ref());
52    let prefix = if with_prefix { "0x" } else { "" };
53    serializer.serialize_str(&format!("{}{}", prefix, hex_str))
54}
55
56pub struct SliceHex;
57
58impl<T> SerializeAs<T> for SliceHex
59where
60    T: AsRef<[u8]>,
61{
62    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
63    where
64        S: Serializer,
65    {
66        to_hex_with_prefix(source, serializer, true)
67    }
68}
69
70impl<'de, T> DeserializeAs<'de, T> for SliceHex
71where
72    T: TryFrom<Vec<u8>>,
73    T::Error: core::fmt::Debug,
74{
75    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
76    where
77        D: Deserializer<'de>,
78    {
79        from_hex(deserializer)
80    }
81}
82
83pub struct SliceHexNoPrefix;
84
85impl<T> SerializeAs<T> for SliceHexNoPrefix
86where
87    T: AsRef<[u8]>,
88{
89    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
90    where
91        S: Serializer,
92    {
93        to_hex_with_prefix(source, serializer, false)
94    }
95}
96
97impl<'de, T> DeserializeAs<'de, T> for SliceHexNoPrefix
98where
99    T: TryFrom<Vec<u8>>,
100    T::Error: core::fmt::Debug,
101{
102    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
103    where
104        D: Deserializer<'de>,
105    {
106        from_hex(deserializer)
107    }
108}
109
110pub struct EntityHex;
111
112impl<T> SerializeAs<T> for EntityHex
113where
114    T: Entity,
115{
116    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
117    where
118        S: Serializer,
119    {
120        to_hex(source.as_slice(), serializer)
121    }
122}
123
124impl<'de, T> DeserializeAs<'de, T> for EntityHex
125where
126    T: Entity,
127{
128    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
129    where
130        D: Deserializer<'de>,
131    {
132        let v: Vec<u8> = from_hex(deserializer)?;
133        T::from_slice(&v).map_err(Error::custom)
134    }
135}
136
137macro_rules! uint_as_hex {
138    ($name:ident, $ty:ty) => {
139        serde_conv!(
140            pub $name,
141            $ty,
142            |u: &$ty| format!("0x{:x}", u),
143            |hex: String| -> Result<$ty, String> {
144                let bytes = hex.as_bytes();
145                if bytes.len() < 3 || &bytes[..2] != b"0x" {
146                    return Err(format!("uint hex string does not start with 0x: {}", hex));
147                }
148                if bytes.len() > 3 && &bytes[2..3] == b"0" {
149                    return Err(format!("uint hex string starts with redundant leading zeros: {}", hex));
150                };
151                <$ty>::from_str_radix(&hex[2..], 16)
152                    .map_err(|err| format!("failed to parse uint hex {}: {:?}", hex, err))
153            }
154        );
155    };
156}
157
158uint_as_hex!(U128Hex, u128);
159uint_as_hex!(U64Hex, u64);
160uint_as_hex!(U32Hex, u32);
161uint_as_hex!(U16Hex, u16);
162
163/// Module for hex serialization of Duration
164pub mod duration_hex {
165    use core::time::Duration;
166    use serde::{Deserialize, Deserializer, Serializer};
167
168    pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
169    where
170        S: Serializer,
171    {
172        let nanos = duration.as_secs();
173        serializer.serialize_str(&format!("0x{:x}", nanos))
174    }
175
176    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
177    where
178        D: Deserializer<'de>,
179    {
180        let hex_str = String::deserialize(deserializer)?;
181        let seconds = u64::from_str_radix(&hex_str[2..], 16).map_err(|err| {
182            serde::de::Error::custom(format!(
183                "failed to parse duration hex {}: {:?}",
184                hex_str, err
185            ))
186        })?;
187
188        Ok(Duration::from_secs(seconds))
189    }
190}
191
192pub struct SliceBase58;
193
194impl<T> SerializeAs<T> for SliceBase58
195where
196    T: AsRef<[u8]>,
197{
198    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
199    where
200        S: Serializer,
201    {
202        serializer.serialize_str(&bs58::encode(source).into_string())
203    }
204}
205
206impl<'de, T> DeserializeAs<'de, T> for SliceBase58
207where
208    T: TryFrom<Vec<u8>>,
209    T::Error: core::fmt::Debug,
210{
211    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
212    where
213        D: Deserializer<'de>,
214    {
215        String::deserialize(deserializer)
216            .and_then(|s| {
217                bs58::decode(&s).into_vec().map_err(|err| {
218                    Error::custom(format!("failed to decode base58 string {}: {:?}", &s, err))
219                })
220            })
221            .and_then(|vec| {
222                vec.try_into().map_err(|err| {
223                    Error::custom(format!("failed to convert vector into type: {:?}", err))
224                })
225            })
226    }
227}
228
229/// Serde helper for serializing `CompactSignature` as raw bytes.
230pub struct CompactSignatureAsBytes;
231
232impl SerializeAs<CompactSignature> for CompactSignatureAsBytes {
233    fn serialize_as<S>(signature: &CompactSignature, serializer: S) -> Result<S::Ok, S::Error>
234    where
235        S: Serializer,
236    {
237        serializer.serialize_bytes(&signature.to_bytes())
238    }
239}
240
241impl<'de> DeserializeAs<'de, CompactSignature> for CompactSignatureAsBytes {
242    fn deserialize_as<D>(deserializer: D) -> Result<CompactSignature, D::Error>
243    where
244        D: Deserializer<'de>,
245    {
246        let bytes: Vec<u8> = Deserialize::deserialize(deserializer)?;
247        if bytes.len() != SCHNORR_SIGNATURE_SIZE {
248            return Err(Error::custom("expected 64 bytes"));
249        }
250        CompactSignature::from_bytes(&bytes).map_err(Error::custom)
251    }
252}
253
254/// Serde helper for serializing `PubNonce` as raw bytes.
255pub struct PubNonceAsBytes;
256
257impl SerializeAs<PubNonce> for PubNonceAsBytes {
258    fn serialize_as<S>(nonce: &PubNonce, serializer: S) -> Result<S::Ok, S::Error>
259    where
260        S: Serializer,
261    {
262        serializer.serialize_bytes(&nonce.to_bytes())
263    }
264}
265
266impl<'de> DeserializeAs<'de, PubNonce> for PubNonceAsBytes {
267    fn deserialize_as<D>(deserializer: D) -> Result<PubNonce, D::Error>
268    where
269        D: Deserializer<'de>,
270    {
271        let bytes: Vec<u8> = Deserialize::deserialize(deserializer)?;
272        if bytes.len() != 66 {
273            return Err(Error::custom("expected 66 bytes"));
274        }
275        PubNonce::from_bytes(&bytes).map_err(Error::custom)
276    }
277}
278
279/// Serde helper for serializing `PartialSignature` as raw bytes.
280pub struct PartialSignatureAsBytes;
281
282impl SerializeAs<PartialSignature> for PartialSignatureAsBytes {
283    fn serialize_as<S>(signature: &PartialSignature, serializer: S) -> Result<S::Ok, S::Error>
284    where
285        S: Serializer,
286    {
287        let bytes: [u8; 32] = signature.serialize();
288        serde::Serialize::serialize(&bytes, serializer)
289    }
290}
291
292impl<'de> DeserializeAs<'de, PartialSignature> for PartialSignatureAsBytes {
293    fn deserialize_as<D>(deserializer: D) -> Result<PartialSignature, D::Error>
294    where
295        D: Deserializer<'de>,
296    {
297        let bytes = <[u8; 32]>::deserialize(deserializer)?;
298        PartialSignature::from_slice(&bytes).map_err(Error::custom)
299    }
300}