p2panda_core/
serde.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::fmt;
4use std::marker::PhantomData;
5
6use serde::de::{Error as SerdeError, SeqAccess, Visitor};
7use serde::ser::SerializeSeq;
8use serde::{Deserialize, Serialize};
9use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes};
10
11use crate::hash::{Hash, HashError};
12use crate::identity::{IdentityError, PrivateKey, PublicKey, Signature};
13use crate::operation::{Body, Header};
14
15/// Helper method for `serde` to serialize bytes into a hex string when using a human readable
16/// encoding (JSON, GraphQL), otherwise it serializes the bytes directly (CBOR).
17pub fn serialize_hex<S>(value: &[u8], serializer: S) -> Result<S::Ok, S::Error>
18where
19    S: serde::Serializer,
20{
21    if serializer.is_human_readable() {
22        hex::serde::serialize(value, serializer)
23    } else {
24        SerdeBytes::new(value).serialize(serializer)
25    }
26}
27
28/// Helper method for `serde` to deserialize from a hex string into bytes when using a human
29/// readable encoding (JSON, GraphQL), otherwise it deserializes the bytes directly (CBOR).
30pub fn deserialize_hex<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
31where
32    D: serde::Deserializer<'de>,
33{
34    if deserializer.is_human_readable() {
35        hex::serde::deserialize(deserializer)
36    } else {
37        let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
38        Ok(bytes.to_vec())
39    }
40}
41
42impl Serialize for Hash {
43    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
44    where
45        S: serde::Serializer,
46    {
47        serialize_hex(self.as_bytes(), serializer)
48    }
49}
50
51impl<'de> Deserialize<'de> for Hash {
52    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53    where
54        D: serde::Deserializer<'de>,
55    {
56        let bytes = deserialize_hex(deserializer)?;
57
58        bytes
59            .as_slice()
60            .try_into()
61            .map_err(|err: HashError| serde::de::Error::custom(err.to_string()))
62    }
63}
64
65impl Serialize for PrivateKey {
66    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67    where
68        S: serde::Serializer,
69    {
70        serialize_hex(self.as_bytes(), serializer)
71    }
72}
73
74impl<'de> Deserialize<'de> for PrivateKey {
75    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76    where
77        D: serde::Deserializer<'de>,
78    {
79        let bytes = deserialize_hex(deserializer)?;
80
81        bytes
82            .as_slice()
83            .try_into()
84            .map_err(|err: IdentityError| serde::de::Error::custom(err.to_string()))
85    }
86}
87
88impl Serialize for PublicKey {
89    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
90    where
91        S: serde::Serializer,
92    {
93        serialize_hex(self.as_bytes(), serializer)
94    }
95}
96
97impl<'de> Deserialize<'de> for PublicKey {
98    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99    where
100        D: serde::Deserializer<'de>,
101    {
102        let bytes = deserialize_hex(deserializer)?;
103
104        bytes
105            .as_slice()
106            .try_into()
107            .map_err(|err: IdentityError| serde::de::Error::custom(err.to_string()))
108    }
109}
110
111impl Serialize for Signature {
112    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
113    where
114        S: serde::Serializer,
115    {
116        serialize_hex(&self.to_bytes(), serializer)
117    }
118}
119
120impl<'de> Deserialize<'de> for Signature {
121    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
122    where
123        D: serde::Deserializer<'de>,
124    {
125        let bytes = deserialize_hex(deserializer)?;
126
127        bytes
128            .as_slice()
129            .try_into()
130            .map_err(|err: IdentityError| serde::de::Error::custom(err.to_string()))
131    }
132}
133
134impl<E> Serialize for Header<E>
135where
136    E: Serialize,
137{
138    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
139    where
140        S: serde::Serializer,
141    {
142        let mut seq = serializer.serialize_seq(Some(self.field_count()))?;
143        seq.serialize_element(&self.version)?;
144        seq.serialize_element(&self.public_key)?;
145
146        if let Some(signature) = &self.signature {
147            seq.serialize_element(signature)?;
148        }
149
150        seq.serialize_element(&self.payload_size)?;
151        if let Some(hash) = &self.payload_hash {
152            seq.serialize_element(&hash)?;
153        }
154
155        seq.serialize_element(&self.timestamp)?;
156        seq.serialize_element(&self.seq_num)?;
157
158        if let Some(backlink) = &self.backlink {
159            seq.serialize_element(backlink)?;
160        }
161
162        seq.serialize_element(&self.previous)?;
163
164        // @TODO: there is an opportunity to skip serializing if `E` is a zero-sized type,
165        // and save one byte.
166        seq.serialize_element(&self.extensions)?;
167
168        seq.end()
169    }
170}
171
172impl<'de, E> Deserialize<'de> for Header<E>
173where
174    E: Deserialize<'de>,
175{
176    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177    where
178        D: serde::Deserializer<'de>,
179    {
180        struct HeaderVisitor<E> {
181            _marker: PhantomData<E>,
182        }
183
184        impl<'de, E> Visitor<'de> for HeaderVisitor<E>
185        where
186            E: Deserialize<'de>,
187        {
188            type Value = Header<E>;
189
190            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
191                formatter.write_str("Header encoded as a sequence")
192            }
193
194            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
195            where
196                A: SeqAccess<'de>,
197            {
198                let version: u64 = seq
199                    .next_element()?
200                    .ok_or(SerdeError::custom("version missing"))?;
201
202                let public_key: PublicKey = seq
203                    .next_element()?
204                    .ok_or(SerdeError::custom("public key missing"))?;
205
206                let signature: Signature = seq
207                    .next_element()?
208                    .ok_or(SerdeError::custom("signature missing"))?;
209
210                let payload_size: u64 = seq
211                    .next_element()?
212                    .ok_or(SerdeError::custom("payload size missing"))?;
213
214                let payload_hash: Option<Hash> = match payload_size {
215                    0 => None,
216                    _ => {
217                        let hash: Hash = seq
218                            .next_element()?
219                            .ok_or(SerdeError::custom("payload hash missing"))?;
220                        Some(hash)
221                    }
222                };
223
224                let timestamp: u64 = seq
225                    .next_element()?
226                    .ok_or(SerdeError::custom("timestamp missing"))?;
227
228                let seq_num: u64 = seq
229                    .next_element()?
230                    .ok_or(SerdeError::custom("sequence number missing"))?;
231
232                let backlink: Option<Hash> = match seq_num {
233                    0 => None,
234                    _ => {
235                        let hash: Hash = seq
236                            .next_element()?
237                            .ok_or(SerdeError::custom("backlink missing"))?;
238                        Some(hash)
239                    }
240                };
241
242                let previous: Vec<Hash> = seq
243                    .next_element()?
244                    .ok_or(SerdeError::custom("previous array missing"))?;
245
246                // @TODO: If `E` is a zero-sized type, use `mem::conjure_zst` when ready.
247                // See https://github.com/rust-lang/rust/pull/146479
248                let extensions: E = seq
249                    .next_element()?
250                    .ok_or(SerdeError::custom("extensions missing"))?;
251
252                Ok(Header {
253                    version,
254                    public_key,
255                    signature: Some(signature),
256                    payload_hash,
257                    payload_size,
258                    timestamp,
259                    seq_num,
260                    backlink,
261                    previous,
262                    extensions,
263                })
264            }
265        }
266
267        deserializer.deserialize_seq(HeaderVisitor::<E> {
268            _marker: PhantomData,
269        })
270    }
271}
272
273impl Serialize for Body {
274    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
275    where
276        S: serde::Serializer,
277    {
278        serialize_hex(&self.0, serializer)
279    }
280}
281
282impl<'de> Deserialize<'de> for Body {
283    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
284    where
285        D: serde::Deserializer<'de>,
286    {
287        let bytes = deserialize_hex(deserializer)?;
288        Ok(Body(bytes.to_vec()))
289    }
290}
291
292#[cfg(test)]
293mod tests {
294    use serde::de::DeserializeOwned;
295    use serde::{Deserialize, Serialize};
296
297    use crate::Body;
298    use crate::hash::Hash;
299    use crate::identity::{PrivateKey, PublicKey};
300    use crate::operation::Header;
301
302    use super::{deserialize_hex, serialize_hex};
303
304    #[derive(Debug, Serialize, Deserialize)]
305    struct Test(
306        #[serde(serialize_with = "serialize_hex", deserialize_with = "deserialize_hex")] Vec<u8>,
307    );
308
309    #[test]
310    fn serialize() {
311        let mut bytes: Vec<u8> = Vec::new();
312        let test = Test(vec![1, 2, 3]);
313
314        // For CBOR the bytes just get serialized straight away as it is not a human readable
315        // encoding
316        ciborium::ser::into_writer(&test, &mut bytes).unwrap();
317        assert_eq!(vec![67, 1, 2, 3], bytes);
318    }
319
320    #[test]
321    fn deserialize() {
322        let bytes: Vec<u8> = vec![67, 1, 2, 3];
323
324        // For CBOR the bytes just get deserialized straight away as an array as it is not a human
325        // readable encoding
326        let test: Test = ciborium::de::from_reader(&bytes[..]).unwrap();
327        assert_eq!(test.0, vec![1, 2, 3]);
328    }
329
330    #[test]
331    fn serialize_hash() {
332        // Serialize CBOR (non human-readable byte encoding)
333        let mut bytes: Vec<u8> = Vec::new();
334        let hash = Hash::new([1, 2, 3]);
335        ciborium::ser::into_writer(&hash, &mut bytes).unwrap();
336        assert_eq!(
337            bytes,
338            vec![
339                88, 32, 177, 119, 236, 27, 242, 109, 251, 59, 112, 16, 212, 115, 230, 212, 71, 19,
340                178, 155, 118, 91, 153, 198, 230, 14, 203, 250, 231, 66, 222, 73, 101, 67
341            ]
342        );
343
344        // Serialize JSON (human-readable hex encoding)
345        let json = serde_json::to_string(&hash).unwrap();
346        assert_eq!(
347            json,
348            "\"b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543\""
349        );
350    }
351
352    #[test]
353    fn deserialize_hash() {
354        // Deserialize CBOR (non human-readable byte encoding)
355        let bytes = [
356            88, 32, 177, 119, 236, 27, 242, 109, 251, 59, 112, 16, 212, 115, 230, 212, 71, 19, 178,
357            155, 118, 91, 153, 198, 230, 14, 203, 250, 231, 66, 222, 73, 101, 67,
358        ];
359        let hash: Hash = ciborium::de::from_reader(&bytes[..]).unwrap();
360        assert_eq!(hash, Hash::new([1, 2, 3]));
361
362        // Deserialize JSON (human-readable hex encoding)
363        let json = "\"b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543\"";
364        let hash: Hash = serde_json::from_str(json).unwrap();
365        assert_eq!(hash, Hash::new([1, 2, 3]));
366    }
367
368    #[test]
369    fn serialize_public_key() {
370        // Serialize CBOR (non human-readable byte encoding)
371        let mut bytes: Vec<u8> = Vec::new();
372        let public_key = PublicKey::from_bytes(&[
373            215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114,
374            243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
375        ])
376        .unwrap();
377        ciborium::ser::into_writer(&public_key, &mut bytes).unwrap();
378        assert_eq!(
379            bytes,
380            vec![
381                88, 32, 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14,
382                225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
383            ]
384        );
385
386        // Serialize JSON (human-readable hex encoding)
387        let json = serde_json::to_string(&public_key).unwrap();
388        assert_eq!(
389            json,
390            "\"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a\""
391        );
392    }
393
394    fn assert_serde_roundtrip<
395        E: Clone + std::fmt::Debug + PartialEq + Serialize + DeserializeOwned,
396    >(
397        mut header: Header<E>,
398        private_key: &PrivateKey,
399    ) {
400        header.sign(private_key);
401
402        let mut bytes = Vec::new();
403        ciborium::ser::into_writer(&header, &mut bytes).unwrap();
404        let header_again: Header<E> = ciborium::de::from_reader(&bytes[..]).unwrap();
405        assert_eq!(header, header_again);
406    }
407
408    #[test]
409    fn serde_roundtrip_operations() {
410        #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
411        struct CustomExtensions {
412            custom_field: u64,
413        }
414
415        let extensions = CustomExtensions { custom_field: 12 };
416        let private_key = PrivateKey::new();
417
418        assert_serde_roundtrip(
419            Header::<CustomExtensions> {
420                version: 1,
421                public_key: private_key.public_key(),
422                payload_size: 123,
423                payload_hash: Some(Hash::new(vec![1, 2, 3])),
424                timestamp: 0,
425                seq_num: 0,
426                backlink: None,
427                previous: vec![],
428                extensions: extensions.clone(),
429                signature: None,
430            },
431            &private_key,
432        );
433
434        assert_serde_roundtrip(
435            Header::<CustomExtensions> {
436                version: 1,
437                public_key: private_key.public_key(),
438                payload_size: 0,
439                payload_hash: None,
440                timestamp: 0,
441                seq_num: 0,
442                backlink: None,
443                previous: vec![],
444                extensions: extensions,
445                signature: None,
446            },
447            &private_key,
448        );
449    }
450
451    #[test]
452    fn expected_de_error() {
453        let private_key = PrivateKey::new();
454
455        // payload size given without payload hash
456        let mut header = Header::<()> {
457            version: 1,
458            public_key: private_key.public_key(),
459            signature: None,
460            payload_size: 2829099,
461            payload_hash: None,
462            timestamp: 0,
463            seq_num: 0,
464            backlink: None,
465            previous: vec![],
466            extensions: (),
467        };
468        header.sign(&private_key);
469
470        let result = ciborium::de::from_reader::<Header<()>, _>(&header.to_bytes()[..]);
471        assert!(result.is_err());
472
473        // payload hash given without payload size
474        let mut header = Header::<()> {
475            version: 1,
476            public_key: private_key.public_key(),
477            signature: None,
478            payload_size: 0,
479            payload_hash: Some(Hash::new([0, 1, 2])),
480            timestamp: 0,
481            seq_num: 0,
482            backlink: None,
483            previous: vec![],
484            extensions: (),
485        };
486        header.sign(&private_key);
487
488        let result = ciborium::de::from_reader::<Header<()>, _>(&header.to_bytes()[..]);
489        assert!(result.is_err());
490
491        // backlink given with seq number 0
492        let mut header = Header::<()> {
493            version: 1,
494            public_key: private_key.public_key(),
495            signature: None,
496            payload_size: 0,
497            payload_hash: None,
498            timestamp: 0,
499            seq_num: 0,
500            backlink: Some(Hash::new([0, 1, 2])),
501            previous: vec![],
502            extensions: (),
503        };
504        header.sign(&private_key);
505
506        let result = ciborium::de::from_reader::<Header<()>, _>(&header.to_bytes()[..]);
507        assert!(result.is_err());
508
509        // backlink not given with seq number > 0
510        let mut header = Header::<()> {
511            version: 1,
512            public_key: private_key.public_key(),
513            signature: None,
514            payload_size: 0,
515            payload_hash: None,
516            timestamp: 0,
517            seq_num: 10,
518            backlink: None,
519            previous: vec![],
520            extensions: (),
521        };
522        header.sign(&private_key);
523
524        let result = ciborium::de::from_reader::<Header<()>, _>(&header.to_bytes()[..]);
525        assert!(result.is_err());
526    }
527
528    #[test]
529    fn serde_header_with_other_types() {
530        let private_key = PrivateKey::new();
531
532        #[derive(Debug, PartialEq, Serialize, Deserialize)]
533        struct Message {
534            header: Header<()>,
535            body: Body,
536        }
537
538        let body = Body::new(b"hello");
539        let mut header = Header::<()> {
540            version: 1,
541            public_key: private_key.public_key(),
542            signature: None,
543            payload_size: body.size(),
544            payload_hash: Some(body.hash()),
545            timestamp: 0,
546            seq_num: 0,
547            backlink: None,
548            previous: vec![],
549            extensions: (),
550        };
551        header.sign(&private_key);
552
553        let message = Message { header, body };
554
555        let mut bytes = Vec::new();
556        ciborium::ser::into_writer(&message, &mut bytes).unwrap();
557
558        let message_again: Message = ciborium::de::from_reader(&bytes[..]).unwrap();
559        assert_eq!(message_again, message);
560    }
561
562    #[test]
563    fn fixtures() {
564        let private_key = PrivateKey::from_bytes(&[
565            244, 123, 85, 215, 161, 204, 94, 227, 239, 253, 128, 164, 228, 160, 195, 49, 18, 49,
566            125, 4, 50, 218, 157, 230, 174, 1, 154, 231, 231, 142, 22, 170,
567        ]);
568
569        // header at seq num 0 with no previous
570        let mut header_0 = Header::<()> {
571            version: 1,
572            public_key: private_key.public_key(),
573            signature: None,
574            payload_size: 0,
575            payload_hash: None,
576            timestamp: 0,
577            seq_num: 0,
578            backlink: None,
579            previous: vec![],
580            extensions: (),
581        };
582        header_0.sign(&private_key);
583
584        let bytes = [
585            136, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
586            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 177,
587            60, 248, 186, 240, 172, 58, 52, 236, 91, 174, 35, 231, 179, 180, 2, 105, 53, 7, 78, 71,
588            179, 99, 159, 171, 47, 250, 15, 242, 228, 75, 39, 112, 204, 138, 63, 88, 171, 227, 239,
589            194, 88, 171, 32, 138, 26, 93, 203, 190, 178, 85, 186, 245, 227, 45, 65, 169, 195, 90,
590            212, 39, 49, 28, 0, 0, 0, 0, 128, 246,
591        ];
592
593        let header_again: Header<()> = ciborium::de::from_reader(&bytes[..]).unwrap();
594        assert_eq!(header_0, header_again);
595
596        // header at seq num 0 with previous
597        let mut header_0_with_previous = Header::<()> {
598            version: 1,
599            public_key: private_key.public_key(),
600            signature: None,
601            payload_size: 0,
602            payload_hash: None,
603            timestamp: 0,
604            seq_num: 0,
605            backlink: None,
606            previous: vec![header_0.hash()],
607            extensions: (),
608        };
609        header_0_with_previous.sign(&private_key);
610
611        let bytes = [
612            136, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
613            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 86,
614            187, 206, 107, 141, 200, 7, 157, 107, 47, 49, 47, 4, 177, 76, 141, 51, 230, 245, 151,
615            124, 185, 157, 79, 59, 59, 14, 91, 105, 6, 229, 145, 62, 167, 203, 221, 253, 28, 128,
616            113, 59, 30, 148, 3, 153, 7, 16, 55, 52, 195, 216, 9, 97, 167, 205, 26, 141, 82, 229,
617            39, 124, 198, 186, 9, 0, 0, 0, 129, 88, 32, 201, 88, 182, 128, 125, 179, 108, 4, 23,
618            151, 168, 52, 216, 181, 123, 95, 11, 78, 75, 6, 236, 167, 141, 219, 243, 115, 255, 203,
619            100, 128, 30, 92, 246,
620        ];
621
622        let header_again: Header<()> = ciborium::de::from_reader(&bytes[..]).unwrap();
623        assert_eq!(header_0_with_previous, header_again);
624
625        // header at seq num 0 with previous and body
626        let body = Body::new("Hello, Sloth!".as_bytes());
627        let mut header_0_with_previous_and_body = Header::<()> {
628            version: 1,
629            public_key: private_key.public_key(),
630            signature: None,
631            payload_size: body.size(),
632            payload_hash: Some(body.hash()),
633            timestamp: 0,
634            seq_num: 0,
635            backlink: None,
636            previous: vec![header_0.hash()],
637            extensions: (),
638        };
639        header_0_with_previous_and_body.sign(&private_key);
640
641        let bytes = [
642            137, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
643            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 152,
644            61, 237, 59, 97, 221, 165, 207, 164, 49, 55, 177, 168, 40, 36, 190, 47, 59, 86, 231,
645            231, 117, 182, 186, 45, 142, 7, 98, 17, 1, 153, 173, 165, 127, 208, 222, 173, 157, 81,
646            165, 228, 184, 230, 165, 88, 173, 41, 104, 171, 12, 18, 57, 179, 18, 254, 50, 65, 226,
647            147, 228, 201, 28, 123, 7, 13, 88, 32, 191, 127, 68, 13, 227, 43, 252, 155, 49, 148,
648            176, 2, 162, 217, 175, 171, 49, 44, 181, 215, 71, 113, 211, 195, 29, 128, 192, 169, 5,
649            138, 160, 142, 0, 0, 129, 88, 32, 201, 88, 182, 128, 125, 179, 108, 4, 23, 151, 168,
650            52, 216, 181, 123, 95, 11, 78, 75, 6, 236, 167, 141, 219, 243, 115, 255, 203, 100, 128,
651            30, 92, 246,
652        ];
653
654        let header_again: Header<()> = ciborium::de::from_reader(&bytes[..]).unwrap();
655        assert_eq!(header_0_with_previous_and_body, header_again);
656
657        // header at seq num 1 with backlink but no previous
658        let mut header_1 = Header::<()> {
659            version: 1,
660            public_key: private_key.public_key(),
661            signature: None,
662            payload_size: 0,
663            payload_hash: None,
664            timestamp: 0,
665            seq_num: 1,
666            backlink: Some(header_0.hash()),
667            previous: vec![],
668            extensions: (),
669        };
670        header_1.sign(&private_key);
671
672        let bytes = [
673            137, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
674            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 159,
675            29, 188, 12, 62, 68, 90, 135, 233, 157, 134, 251, 205, 180, 206, 144, 230, 240, 161,
676            42, 236, 217, 77, 210, 161, 229, 92, 67, 213, 170, 105, 53, 16, 57, 43, 62, 143, 162,
677            177, 91, 154, 154, 131, 45, 138, 152, 49, 80, 42, 144, 249, 30, 166, 143, 139, 255, 54,
678            65, 180, 15, 102, 222, 210, 6, 0, 0, 1, 88, 32, 201, 88, 182, 128, 125, 179, 108, 4,
679            23, 151, 168, 52, 216, 181, 123, 95, 11, 78, 75, 6, 236, 167, 141, 219, 243, 115, 255,
680            203, 100, 128, 30, 92, 128, 246,
681        ];
682
683        let header_again: Header<()> = ciborium::de::from_reader(&bytes[..]).unwrap();
684        assert_eq!(header_1, header_again);
685
686        // header at seq num 1 with previous
687        let mut header_1_with_previous = Header::<()> {
688            version: 1,
689            public_key: private_key.public_key(),
690            signature: None,
691            payload_size: 0,
692            payload_hash: None,
693            timestamp: 0,
694            seq_num: 1,
695            backlink: Some(header_0.hash()),
696            previous: vec![header_0.hash()],
697            extensions: (),
698        };
699        header_1_with_previous.sign(&private_key);
700
701        let bytes = [
702            137, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
703            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 147,
704            144, 109, 231, 188, 44, 47, 38, 189, 192, 85, 151, 242, 49, 40, 30, 155, 198, 216, 52,
705            140, 216, 65, 66, 19, 227, 159, 175, 23, 107, 113, 180, 100, 44, 161, 228, 126, 219,
706            10, 85, 71, 59, 156, 117, 23, 1, 101, 224, 96, 75, 45, 25, 17, 37, 56, 78, 184, 120,
707            39, 115, 95, 127, 83, 3, 0, 0, 1, 88, 32, 201, 88, 182, 128, 125, 179, 108, 4, 23, 151,
708            168, 52, 216, 181, 123, 95, 11, 78, 75, 6, 236, 167, 141, 219, 243, 115, 255, 203, 100,
709            128, 30, 92, 129, 88, 32, 201, 88, 182, 128, 125, 179, 108, 4, 23, 151, 168, 52, 216,
710            181, 123, 95, 11, 78, 75, 6, 236, 167, 141, 219, 243, 115, 255, 203, 100, 128, 30, 92,
711            246,
712        ];
713
714        let header_again: Header<()> = ciborium::de::from_reader(&bytes[..]).unwrap();
715        assert_eq!(header_1_with_previous, header_again);
716    }
717
718    #[test]
719    fn decode_non_map_extensions() {
720        let private_key = PrivateKey::new();
721
722        let mut header = Header::<()> {
723            version: 1,
724            public_key: private_key.public_key(),
725            signature: None,
726            payload_size: 0,
727            payload_hash: None,
728            timestamp: 0,
729            seq_num: 0,
730            backlink: None,
731            previous: vec![],
732            extensions: (),
733        };
734        header.sign(&private_key);
735
736        let result = ciborium::de::from_reader::<Header<()>, _>(&header.to_bytes()[..]);
737        assert!(result.is_ok());
738    }
739
740    #[test]
741    fn unexpected_eof_when_incomplete() {
742        // ciborium should be able to detect an "Unexpected EOF" error if we're giving it an
743        // incomplete header.
744        let incomplete = [
745            137, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
746        ];
747
748        let result: Result<Header<()>, _> = ciborium::de::from_reader(&incomplete[..]);
749        assert!(matches!(result, Err(ciborium::de::Error::Io(_))));
750    }
751}