Skip to main content

mls_spec/drafts/
associated_parties.rs

1use crate::{
2    SensitiveBytes,
3    crypto::{HpkePublicKey, HpkePublicKeyRef},
4    defs::SenderIndex,
5    group::ExternalSender,
6    key_schedule::GroupContext,
7};
8
9use super::mls_extensions::safe_application::{Component, ComponentId};
10
11pub const COMPONENT_ID: ComponentId = 0x0007;
12
13#[derive(Debug, Clone, PartialEq, Eq, tls_codec::TlsSize, tls_codec::TlsSerialize)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize))]
15pub struct AssociatedPartyEntryTBS<'a> {
16    pub encryption_key: HpkePublicKeyRef<'a>,
17    pub external_sender_index: &'a SenderIndex,
18}
19
20#[derive(
21    Debug,
22    Clone,
23    PartialEq,
24    Eq,
25    tls_codec::TlsSize,
26    tls_codec::TlsSerialize,
27    tls_codec::TlsDeserialize,
28)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub struct AssociatedPartyEntry {
31    pub encryption_key: HpkePublicKey,
32    pub external_sender_index: SenderIndex,
33    pub signature: SensitiveBytes,
34}
35
36impl AssociatedPartyEntry {
37    pub fn to_tbs(&self) -> AssociatedPartyEntryTBS<'_> {
38        AssociatedPartyEntryTBS {
39            encryption_key: &self.encryption_key,
40            external_sender_index: &self.external_sender_index,
41        }
42    }
43
44    /// Finds the related `ExternalSender` from the provided `GroupContext`.
45    ///
46    /// If this returns `None`, then you can safely consider the AssociatedParty to be invalid!
47    pub fn related_external_sender_from_group_context<'a>(
48        &self,
49        ctx: &'a GroupContext,
50    ) -> Option<&'a ExternalSender> {
51        ctx.external_senders()
52            .get(self.external_sender_index as usize)
53    }
54}
55
56#[derive(
57    Debug,
58    Clone,
59    PartialEq,
60    Eq,
61    tls_codec::TlsSize,
62    tls_codec::TlsSerialize,
63    tls_codec::TlsDeserialize,
64)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66pub struct AssociatedParties {
67    pub associated_parties: Vec<AssociatedPartyEntry>,
68}
69
70impl Component for AssociatedParties {
71    fn component_id() -> ComponentId {
72        COMPONENT_ID
73    }
74}
75
76pub mod proposals {
77    use crate::defs::LeafIndex;
78
79    use super::AssociatedPartyEntry;
80
81    #[derive(
82        Debug,
83        Clone,
84        PartialEq,
85        Eq,
86        tls_codec::TlsSize,
87        tls_codec::TlsSerialize,
88        tls_codec::TlsDeserialize,
89    )]
90    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91    pub struct AddAssociatedPartyProposal {
92        pub new_party: AssociatedPartyEntry,
93    }
94
95    #[derive(
96        Debug,
97        Clone,
98        Copy,
99        PartialEq,
100        Eq,
101        tls_codec::TlsSize,
102        tls_codec::TlsSerialize,
103        tls_codec::TlsDeserialize,
104    )]
105    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106    pub struct RemoveAssociatedPartyProposal {
107        pub removed_party_index: LeafIndex,
108    }
109
110    #[derive(
111        Debug,
112        Clone,
113        PartialEq,
114        Eq,
115        tls_codec::TlsSize,
116        tls_codec::TlsSerialize,
117        tls_codec::TlsDeserialize,
118    )]
119    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
120    pub struct UpdateAssociatedPartyProposal {
121        pub updated_party: AssociatedPartyEntry,
122    }
123}
124
125pub mod key_schedule {
126    use crate::{SensitiveBytes, defs::LeafIndex, key_schedule::GroupContext};
127
128    use super::AssociatedPartyEntry;
129
130    #[derive(Debug, Clone, Copy, PartialEq, Eq, tls_codec::TlsSize, tls_codec::TlsSerialize)]
131    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
132    pub struct AssociatedPartyExportContext<'a> {
133        pub ap_index: &'a LeafIndex,
134        pub ap_entry: &'a AssociatedPartyEntry,
135    }
136
137    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
138    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
139    pub struct AssociatedPartyEncryptionContext<'a> {
140        pub group_context: &'a GroupContext,
141        pub ap_commit_secret_id: &'a [u8],
142    }
143
144    impl AssociatedPartyEncryptionContext<'_> {
145        pub const LABEL: &'static [u8] = b"AP Commit Secret";
146    }
147
148    impl tls_codec::Size for AssociatedPartyEncryptionContext<'_> {
149        fn tls_serialized_len(&self) -> usize {
150            crate::tlspl::tls_serialized_len_as_vlvec(Self::LABEL.len())
151                + self.group_context.tls_serialized_len()
152                + crate::tlspl::tls_serialized_len_as_vlvec(self.ap_commit_secret_id.len())
153        }
154    }
155
156    impl tls_codec::Serialize for AssociatedPartyEncryptionContext<'_> {
157        fn tls_serialize<W: std::io::Write>(
158            &self,
159            writer: &mut W,
160        ) -> Result<usize, tls_codec::Error> {
161            let mut written = crate::tlspl::bytes::tls_serialize(Self::LABEL, writer)?;
162            written += self.group_context.tls_serialize(writer)?;
163            written += crate::tlspl::bytes::tls_serialize(self.ap_commit_secret_id, writer)?;
164            Ok(written)
165        }
166    }
167
168    #[derive(
169        Debug,
170        Clone,
171        PartialEq,
172        Eq,
173        tls_codec::TlsSize,
174        tls_codec::TlsSerialize,
175        tls_codec::TlsDeserialize,
176    )]
177    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
178    pub struct AssociatedPartySecret {
179        pub associated_party_proposal_secret: SensitiveBytes,
180    }
181
182    #[derive(
183        Debug,
184        Clone,
185        PartialEq,
186        Eq,
187        tls_codec::TlsSize,
188        tls_codec::TlsSerialize,
189        tls_codec::TlsDeserialize,
190    )]
191    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
192    pub struct AssociatedPartySecrets {
193        pub associated_party_init_secret: SensitiveBytes,
194    }
195}