bc_envelope/base/
cbor.rs

1#[cfg(feature = "compress")]
2use bc_components::Compressed;
3#[cfg(feature = "encrypt")]
4use bc_components::EncryptedMessage;
5use bc_components::{Digest, tags};
6use dcbor::prelude::*;
7
8use super::envelope::EnvelopeCase;
9#[cfg(feature = "known_value")]
10use crate::extension::KnownValue;
11use crate::{Assertion, Envelope};
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> { tags_for_values(&[tags::TAG_ENVELOPE]) }
28}
29
30impl From<Envelope> for CBOR {
31    fn from(value: Envelope) -> Self { value.tagged_cbor() }
32}
33
34impl TryFrom<CBOR> for Envelope {
35    type Error = dcbor::Error;
36
37    fn try_from(value: CBOR) -> dcbor::Result<Self> {
38        Self::from_tagged_cbor(value)
39    }
40}
41
42impl CBORTaggedEncodable for Envelope {
43    fn untagged_cbor(&self) -> CBOR {
44        match self.case() {
45            EnvelopeCase::Node { subject, assertions, digest: _ } => {
46                let mut result = vec![subject.untagged_cbor()];
47                for assertion in assertions {
48                    result.push(assertion.untagged_cbor());
49                }
50                CBORCase::Array(result).into()
51            }
52            EnvelopeCase::Leaf { cbor, digest: _ } => {
53                CBOR::to_tagged_value(tags::TAG_LEAF, cbor.clone())
54            }
55            EnvelopeCase::Wrapped { envelope, digest: _ } => {
56                envelope.tagged_cbor()
57            }
58            EnvelopeCase::Assertion(assertion) => assertion.clone().into(),
59            EnvelopeCase::Elided(digest) => digest.untagged_cbor(),
60            #[cfg(feature = "known_value")]
61            EnvelopeCase::KnownValue { value, digest: _ } => {
62                value.untagged_cbor()
63            }
64            #[cfg(feature = "encrypt")]
65            EnvelopeCase::Encrypted(encrypted_message) => {
66                encrypted_message.tagged_cbor()
67            }
68            #[cfg(feature = "compress")]
69            EnvelopeCase::Compressed(compressed) => compressed.tagged_cbor(),
70        }
71    }
72}
73
74impl CBORTaggedDecodable for Envelope {
75    fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
76        match cbor.as_case() {
77            CBORCase::Tagged(tag, item) => match tag.value() {
78                tags::TAG_LEAF | tags::TAG_ENCODED_CBOR => {
79                    Ok(Self::new_leaf(item.clone()))
80                }
81                tags::TAG_ENVELOPE => {
82                    let envelope = Envelope::try_from(cbor)?;
83                    Ok(Self::new_wrapped(envelope))
84                }
85                #[cfg(feature = "encrypt")]
86                tags::TAG_ENCRYPTED => {
87                    let encrypted =
88                        EncryptedMessage::from_untagged_cbor(item.clone())?;
89                    let envelope = Self::new_with_encrypted(encrypted)
90                        .map_err(|e| e.to_string())?;
91                    Ok(envelope)
92                }
93                #[cfg(feature = "compress")]
94                tags::TAG_COMPRESSED => {
95                    let compressed =
96                        Compressed::from_untagged_cbor(item.clone())?;
97                    let envelope = Self::new_with_compressed(compressed)
98                        .map_err(|e| e.to_string())?;
99                    Ok(envelope)
100                }
101                _ => {
102                    Err(format!("unknown envelope tag: {}", tag.value()).into())
103                }
104            },
105            CBORCase::ByteString(bytes) => {
106                Ok(Self::new_elided(Digest::from_data_ref(bytes)?))
107            }
108            CBORCase::Array(elements) => {
109                if elements.len() < 2 {
110                    return Err("node must have at least two elements".into());
111                }
112                let subject = Self::from_untagged_cbor(elements[0].clone())?;
113                let assertions: Vec<Envelope> = elements[1..]
114                    .iter()
115                    .cloned()
116                    .map(Self::from_untagged_cbor)
117                    .collect::<dcbor::Result<Vec<Self>>>()?;
118                Ok(Self::new_with_assertions(subject, assertions)
119                    .map_err(|e| e.to_string())?)
120            }
121            CBORCase::Map(_) => {
122                let assertion =
123                    Assertion::try_from(cbor).map_err(|e| e.to_string())?;
124                Ok(Self::new_with_assertion(assertion))
125            }
126            #[cfg(feature = "known_value")]
127            CBORCase::Unsigned(value) => {
128                let known_value = KnownValue::new(*value);
129                Ok(Self::new_with_known_value(known_value))
130            }
131            _ => Err("invalid envelope".into()),
132        }
133    }
134}