p2panda_core/
serde.rs

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