vrf_wasm/
serde_helpers.rs

1// Copyright (c) 2022, Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use serde::{Deserialize, Serialize};
5use serde_with::serde_as;
6use crate::error::FastCryptoError;
7
8// Serde treats arrays larger than 32 as variable length arrays, and adds the length as a prefix.
9// Since we want a fixed size representation, we wrap it in this helper struct and use serde_as.
10#[serde_as]
11#[derive(Serialize, Deserialize)]
12#[serde(transparent)]
13pub struct SerializationHelper<const N: usize>(#[serde_as(as = "[_; N]")] pub [u8; N]);
14
15pub trait ToFromByteArray<const LENGTH: usize>: Sized {
16    const BYTE_LENGTH: usize = LENGTH;
17    fn from_byte_array(bytes: &[u8; LENGTH]) -> Result<Self, FastCryptoError>;
18    fn to_byte_array(&self) -> [u8; LENGTH];
19}
20
21/// Macro for generating Serialize/Deserialize for a type that implements [ToFromByteArray].
22#[macro_export]
23macro_rules! serialize_deserialize_with_to_from_byte_array {
24    ($type:ty) => {
25        impl ::serde::Serialize for $type {
26            fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
27                use $crate::encoding::Base64;
28                use $crate::encoding::Encoding;
29                use $crate::serde_helpers::SerializationHelper;
30
31                let bytes = &self.to_byte_array();
32                match serializer.is_human_readable() {
33                    true => Base64::encode(bytes).serialize(serializer),
34                    false => SerializationHelper::<{ <$type>::BYTE_LENGTH }>(*bytes)
35                        .serialize(serializer),
36                }
37            }
38        }
39
40        impl<'de> ::serde::Deserialize<'de> for $type {
41            fn deserialize<D: ::serde::Deserializer<'de>>(
42                deserializer: D,
43            ) -> Result<Self, D::Error> {
44                use $crate::encoding::Base64;
45                use $crate::encoding::Encoding;
46                use $crate::serde_helpers::SerializationHelper;
47
48                let bytes = match deserializer.is_human_readable() {
49                    true => {
50                        let s = String::deserialize(deserializer)?;
51                        let decoded = Base64::decode(&s)
52                            .map_err(|_| de::Error::custom("Base64 decoding failed"))?;
53                        if decoded.len() != { <$type>::BYTE_LENGTH } {
54                            return Err(de::Error::custom(format!(
55                                "Invalid buffer length {}, expecting {}",
56                                decoded.len(),
57                                { <$type>::BYTE_LENGTH }
58                            )));
59                        }
60                        decoded.try_into().unwrap()
61                    }
62                    false => {
63                        let helper: SerializationHelper<{ <$type>::BYTE_LENGTH }> =
64                            Deserialize::deserialize(deserializer)?;
65                        helper.0
66                    }
67                };
68                Self::from_byte_array(&bytes)
69                    .map_err(|_| de::Error::custom("Failed in reconstructing the object"))
70            }
71        }
72    };
73}
74
75#[macro_export]
76macro_rules! serialize_deserialize_with_to_from_bytes {
77    ($type:ty, $length:tt) => {
78        impl ::serde::Serialize for $type {
79            fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
80                use $crate::serde_helpers::SerializationHelper;
81                match serializer.is_human_readable() {
82                    true => serializer.serialize_str(&self.encode_base64()),
83                    false => SerializationHelper::<{ $length }>(self.as_ref().try_into().unwrap())
84                        .serialize(serializer),
85                }
86            }
87        }
88
89        impl<'de> ::serde::Deserialize<'de> for $type {
90            fn deserialize<D: ::serde::Deserializer<'de>>(
91                deserializer: D,
92            ) -> Result<Self, D::Error> {
93                use serde::Deserialize;
94                use $crate::serde_helpers::SerializationHelper;
95                if deserializer.is_human_readable() {
96                    let s = <String as ::serde::Deserialize>::deserialize(deserializer)?;
97                    Self::decode_base64(&s).map_err(::serde::de::Error::custom)
98                } else {
99                    let helper: SerializationHelper<{ $length }> =
100                        Deserialize::deserialize(deserializer)?;
101                    <Self as ToFromBytes>::from_bytes(&helper.0).map_err(::serde::de::Error::custom)
102                }
103            }
104        }
105    };
106}