bc_envelope/base/
cbor.rs

1use bc_components::{tags, Digest};
2#[cfg(feature = "encrypt")]
3use bc_components::EncryptedMessage;
4#[cfg(feature = "compress")]
5use bc_components::Compressed;
6use dcbor::prelude::*;
7use crate::{Assertion, Envelope};
8#[cfg(feature = "known_value")]
9use crate::extension::KnownValue;
10
11use super::envelope::EnvelopeCase;
12
13/// Support for CBOR encoding and decoding of ``Envelope``.
14///
15/// All envelopes are tagged with the `envelope` tag. Within that tag, each of
16/// the seven cases has a unique CBOR signature:
17///
18/// * `.node` contains a CBOR array, the first element of which is the subject,
19///     followed by one or more assertions.
20/// * `.leaf` is tagged #6.24, which is the IANA tag for embedded CBOR.
21/// * `.wrapped` is tagged with the `envelope` tag.
22/// * `.assertion` is a single-element map `{predicate: object}`.
23/// * `.knownValue` is an unsigned 64-bit integer.
24/// * `.encrypted` is tagged with the `crypto-msg` tag.
25/// * `.elided` is a byte string of length 32.
26impl CBORTagged for Envelope {
27    fn cbor_tags() -> Vec<Tag> {
28        tags_for_values(&[tags::TAG_ENVELOPE])
29    }
30}
31
32impl From<Envelope> for CBOR {
33    fn from(value: Envelope) -> Self {
34        value.tagged_cbor()
35    }
36}
37
38impl TryFrom<CBOR> for Envelope {
39    type Error = dcbor::Error;
40
41    fn try_from(value: CBOR) -> dcbor::Result<Self> {
42        Self::from_tagged_cbor(value)
43    }
44}
45
46impl CBORTaggedEncodable for Envelope {
47    fn untagged_cbor(&self) -> CBOR {
48        match self.case() {
49            EnvelopeCase::Node { subject, assertions, digest: _ } => {
50                let mut result = vec![subject.untagged_cbor()];
51                for assertion in assertions {
52                    result.push(assertion.untagged_cbor());
53                }
54                CBORCase::Array(result).into()
55            }
56            EnvelopeCase::Leaf { cbor, digest: _ } => CBOR::to_tagged_value(tags::TAG_LEAF, cbor.clone()),
57            EnvelopeCase::Wrapped { envelope, digest: _ } => envelope.tagged_cbor(),
58            EnvelopeCase::Assertion(assertion) => assertion.clone().into(),
59            EnvelopeCase::Elided(digest) => digest.untagged_cbor(),
60            #[cfg(feature = "known_value")]
61            EnvelopeCase::KnownValue { value, digest: _ } => value.untagged_cbor(),
62            #[cfg(feature = "encrypt")]
63            EnvelopeCase::Encrypted(encrypted_message) => encrypted_message.tagged_cbor(),
64            #[cfg(feature = "compress")]
65            EnvelopeCase::Compressed(compressed) => compressed.tagged_cbor(),
66        }
67    }
68}
69
70impl CBORTaggedDecodable for Envelope {
71    fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
72        match cbor.as_case() {
73            CBORCase::Tagged(tag, item) => {
74                match tag.value() {
75                    tags::TAG_LEAF | tags::TAG_ENCODED_CBOR => {
76                        Ok(Self::new_leaf(item.clone()))
77                    },
78                    tags::TAG_ENVELOPE => {
79                        let envelope = Envelope::try_from(cbor)?;
80                        Ok(Self::new_wrapped(envelope))
81                    },
82                    #[cfg(feature = "encrypt")]
83                    tags::TAG_ENCRYPTED => {
84                        let encrypted = EncryptedMessage::from_untagged_cbor(item.clone())?;
85                        let envelope = Self::new_with_encrypted(encrypted)?;
86                        Ok(envelope)
87                    },
88                    #[cfg(feature = "compress")]
89                    tags::TAG_COMPRESSED => {
90                        let compressed = Compressed::from_untagged_cbor(item.clone())?;
91                        let envelope = Self::new_with_compressed(compressed)?;
92                        Ok(envelope)
93                    },
94                    _ => return Err(format!("unknown envelope tag: {}", tag.value()).into()),
95                }
96            }
97            CBORCase::ByteString(bytes) => {
98                Ok(Self::new_elided(Digest::from_data_ref(bytes)?))
99            }
100            CBORCase::Array(elements) => {
101                if elements.len() < 2 {
102                    return Err("node must have at least two elements".into());
103                }
104                let subject = Self::from_untagged_cbor(elements[0].clone())?;
105                let assertions: Vec<Envelope> = elements[1..]
106                    .iter()
107                    .cloned()
108                    .map(Self::from_untagged_cbor)
109                    .collect::<dcbor::Result<Vec<Self>>>()?;
110                Ok(Self::new_with_assertions(subject, assertions)?)
111            }
112            CBORCase::Map(_) => {
113                let assertion = Assertion::try_from(cbor)?;
114                Ok(Self::new_with_assertion(assertion))
115            }
116            #[cfg(feature = "known_value")]
117            CBORCase::Unsigned(value) => {
118                let known_value = KnownValue::new(*value);
119                Ok(Self::new_with_known_value(known_value))
120            }
121            _ => return Err("invalid envelope".into()),
122        }
123    }
124}