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