Skip to main content

quantum_shield/
serde_impls.rs

1//! Optional serde support: wire types serialize as their binary encoding.
2//!
3//! With the `serde` feature enabled, [`Envelope`], [`HybridSignature`], and
4//! [`PublicKeyBundle`] implement `Serialize`/`Deserialize` as byte sequences
5//! containing exactly their `to_bytes()` form, so all format validation runs
6//! on deserialization.
7
8use crate::{Envelope, HybridSignature, PublicKeyBundle};
9use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
10
11macro_rules! impl_serde_via_bytes {
12    ($type:ty) => {
13        impl Serialize for $type {
14            fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
15                serializer.serialize_bytes(&self.to_bytes())
16            }
17        }
18
19        impl<'de> Deserialize<'de> for $type {
20            fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
21                let bytes = <serde_bytes_shim::ByteBuf as Deserialize>::deserialize(deserializer)?;
22                <$type>::from_bytes(&bytes.0).map_err(de::Error::custom)
23            }
24        }
25    };
26}
27
28/// Minimal stand-in for `serde_bytes`: accepts both byte buffers and
29/// sequences of integers, so the impls work with self-describing formats
30/// (JSON arrays) and binary formats (bincode, CBOR byte strings) alike.
31mod serde_bytes_shim {
32    use alloc::vec::Vec;
33    use serde::{de, Deserialize, Deserializer};
34
35    pub(super) struct ByteBuf(pub(super) Vec<u8>);
36
37    impl<'de> Deserialize<'de> for ByteBuf {
38        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
39            struct Visitor;
40
41            impl<'de> de::Visitor<'de> for Visitor {
42                type Value = ByteBuf;
43
44                fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45                    f.write_str("bytes")
46                }
47
48                fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<ByteBuf, E> {
49                    Ok(ByteBuf(v.to_vec()))
50                }
51
52                fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<ByteBuf, E> {
53                    Ok(ByteBuf(v))
54                }
55
56                fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<ByteBuf, A::Error> {
57                    // Cap the pre-allocation: `size_hint` is attacker-controlled
58                    // for self-describing binary formats (bincode/CBOR), so a
59                    // tiny blob could otherwise request a huge up-front alloc.
60                    // The Vec still grows as elements arrive.
61                    let hint = seq.size_hint().unwrap_or(0).min(64 * 1024);
62                    let mut out = Vec::with_capacity(hint);
63                    while let Some(b) = seq.next_element::<u8>()? {
64                        out.push(b);
65                    }
66                    Ok(ByteBuf(out))
67                }
68            }
69
70            deserializer.deserialize_byte_buf(Visitor)
71        }
72    }
73}
74
75impl_serde_via_bytes!(Envelope);
76impl_serde_via_bytes!(HybridSignature);
77impl_serde_via_bytes!(PublicKeyBundle);
78
79#[cfg(test)]
80mod tests {
81    use crate::{seal, Envelope, HybridCrypto, HybridSignature, PublicKeyBundle};
82
83    #[test]
84    fn json_roundtrip_all_wire_types() {
85        let kp = HybridCrypto::generate().unwrap();
86
87        let envelope = seal(b"serde test", kp.public_keys()).unwrap();
88        let json = serde_json::to_string(&envelope).unwrap();
89        let back: Envelope = serde_json::from_str(&json).unwrap();
90        assert_eq!(kp.open(&back).unwrap(), b"serde test");
91
92        let sig = kp.sign(b"msg", b"").unwrap();
93        let json = serde_json::to_string(&sig).unwrap();
94        let back: HybridSignature = serde_json::from_str(&json).unwrap();
95        assert_eq!(back, sig);
96
97        let json = serde_json::to_string(kp.public_keys()).unwrap();
98        let back: PublicKeyBundle = serde_json::from_str(&json).unwrap();
99        assert_eq!(&back, kp.public_keys());
100    }
101
102    #[test]
103    fn deserialization_validates() {
104        // A corrupted byte stream must fail through the same validation as
105        // from_bytes, not produce a half-parsed object.
106        let kp = HybridCrypto::generate().unwrap();
107        let mut bytes = kp.public_keys().to_bytes();
108        bytes[0] = b'X'; // break magic
109        let json = serde_json::to_string(&bytes).unwrap();
110        assert!(serde_json::from_str::<PublicKeyBundle>(&json).is_err());
111    }
112}