mls_spec/group/
group_info.rs

1use crate::{
2    SensitiveBytes,
3    crypto::Mac,
4    defs::{LeafIndex, ProtocolVersion},
5    group::extensions::{Extension, ExternalPub, RatchetTreeExtension},
6    key_schedule::GroupContext,
7    messages::MlsMessage,
8    tree::RatchetTree,
9};
10
11#[derive(Debug, Clone, PartialEq, Eq, tls_codec::TlsSerialize, tls_codec::TlsSize)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize))]
13pub struct GroupInfoTBS<'a> {
14    pub group_context: &'a GroupContext,
15    pub extensions: &'a [Extension],
16    pub confirmation_tag: &'a Mac,
17    pub signer: &'a LeafIndex,
18}
19
20#[derive(
21    Debug,
22    Clone,
23    PartialEq,
24    Eq,
25    tls_codec::TlsSerialize,
26    tls_codec::TlsDeserialize,
27    tls_codec::TlsSize,
28)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub struct GroupInfo {
31    pub group_context: GroupContext,
32    pub extensions: Vec<Extension>,
33    pub confirmation_tag: Mac,
34    pub signer: LeafIndex,
35    pub signature: SensitiveBytes,
36}
37
38impl GroupInfo {
39    pub fn to_tbs(&self) -> GroupInfoTBS<'_> {
40        GroupInfoTBS {
41            group_context: &self.group_context,
42            extensions: &self.extensions,
43            confirmation_tag: &self.confirmation_tag,
44            signer: &self.signer,
45        }
46    }
47
48    /// Returns the RatchetTree extension if present
49    pub fn ratchet_tree(&self) -> Option<&RatchetTree> {
50        self.extensions.iter().find_map(|ext| {
51            if let Extension::RatchetTree(RatchetTreeExtension { ratchet_tree }) = ext {
52                Some(ratchet_tree)
53            } else {
54                None
55            }
56        })
57    }
58
59    /// Returns the ExternalPub extension if present
60    pub fn external_pub(&self) -> Option<&[u8]> {
61        self.extensions.iter().find_map(|ext| {
62            if let Extension::ExternalPub(ExternalPub { external_pub }) = ext {
63                Some(external_pub.as_slice())
64            } else {
65                None
66            }
67        })
68    }
69
70    pub fn into_mls_message(self, protocol_version: ProtocolVersion) -> MlsMessage {
71        MlsMessage {
72            version: protocol_version,
73            content: crate::messages::MlsMessageContent::GroupInfo(self),
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use crate::generate_roundtrip_test;
81
82    use super::*;
83
84    generate_roundtrip_test!(can_roundtrip_groupinfo, {
85        GroupInfo {
86            group_context: GroupContext::with_group_id(vec![]),
87            extensions: vec![],
88            confirmation_tag: vec![].into(),
89            signer: 0,
90            signature: vec![].into(),
91        }
92    });
93}