nucypher_core/
threshold_message_kit.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4
5use ferveo::api::{Ciphertext, CiphertextHeader, SharedSecret};
6use ferveo::Error;
7use serde::{Deserialize, Serialize};
8
9use crate::access_control::AccessControlPolicy;
10use crate::versioning::{
11    messagepack_deserialize, messagepack_serialize, ProtocolObject, ProtocolObjectInner,
12};
13
14/// Access control metadata for encrypted data.
15#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
16pub struct ThresholdMessageKit {
17    /// The key encapsulation ciphertext
18    pub ciphertext: Ciphertext,
19
20    /// The associated access control metadata.
21    pub acp: AccessControlPolicy,
22}
23
24impl ThresholdMessageKit {
25    /// Creates a new threshold message kit.
26    pub fn new(ciphertext: &Ciphertext, acp: &AccessControlPolicy) -> Self {
27        ThresholdMessageKit {
28            ciphertext: ciphertext.clone(),
29            acp: acp.clone(),
30        }
31    }
32
33    /// Returns ciphertext header.
34    pub fn ciphertext_header(&self) -> Result<CiphertextHeader, Error> {
35        self.ciphertext.header()
36    }
37
38    /// Decrypts encrypted data.
39    pub fn decrypt_with_shared_secret(
40        &self,
41        shared_secret: &SharedSecret,
42    ) -> Result<Vec<u8>, Error> {
43        ferveo::api::decrypt_with_shared_secret(
44            &self.ciphertext,
45            self.acp.aad()?.as_ref(),
46            shared_secret,
47        )
48    }
49}
50
51impl<'a> ProtocolObjectInner<'a> for ThresholdMessageKit {
52    fn version() -> (u16, u16) {
53        (1, 0)
54    }
55
56    fn brand() -> [u8; 4] {
57        *b"TMKi"
58    }
59
60    fn unversioned_to_bytes(&self) -> Box<[u8]> {
61        messagepack_serialize(&self)
62    }
63
64    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
65        if minor_version == 0 {
66            Some(messagepack_deserialize(bytes))
67        } else {
68            None
69        }
70    }
71}
72
73impl<'a> ProtocolObject<'a> for ThresholdMessageKit {}
74
75#[cfg(test)]
76mod tests {
77    use ferveo::api::{encrypt as ferveo_encrypt, SecretBox};
78
79    use crate::access_control::{AccessControlPolicy, AuthenticatedData};
80    use crate::conditions::Conditions;
81    use crate::test_utils::util::random_dkg_pubkey;
82    use crate::threshold_message_kit::ThresholdMessageKit;
83    use crate::versioning::ProtocolObject;
84    #[test]
85    fn threshold_message_kit() {
86        let dkg_pk = random_dkg_pubkey();
87        let data = "The Tyranny of Merit".as_bytes().to_vec();
88
89        let authorization = b"we_dont_need_no_stinking_badges";
90        let acp = AccessControlPolicy::new(
91            &AuthenticatedData::new(&dkg_pk, &Conditions::new("abcd")),
92            authorization,
93        );
94
95        let ciphertext =
96            ferveo_encrypt(SecretBox::new(data), &acp.aad().unwrap(), &dkg_pk).unwrap();
97        let tmk = ThresholdMessageKit::new(&ciphertext, &acp);
98
99        // mimic serialization/deserialization over the wire
100        let serialized_tmk = tmk.to_bytes();
101        let deserialized_tmk = ThresholdMessageKit::from_bytes(&serialized_tmk).unwrap();
102        assert_eq!(
103            ciphertext.header().unwrap(),
104            deserialized_tmk.ciphertext_header().unwrap()
105        );
106        assert_eq!(acp, deserialized_tmk.acp);
107    }
108}