openmls/group/
group_context.rs1use openmls_traits::crypto::OpenMlsCrypto;
4use openmls_traits::types::Ciphersuite;
5
6use super::*;
7#[cfg(feature = "extensions-draft-08")]
8use crate::extensions::AppDataDictionary;
9use crate::{
10 error::LibraryError,
11 framing::{mls_auth_content::AuthenticatedContent, ConfirmedTranscriptHashInput},
12 versions::ProtocolVersion,
13};
14
15#[derive(
32 Debug,
33 Clone,
34 PartialEq,
35 Eq,
36 Serialize,
37 Deserialize,
38 TlsSerialize,
39 TlsDeserialize,
40 TlsDeserializeBytes,
41 TlsSize,
42)]
43pub struct GroupContext {
44 protocol_version: ProtocolVersion,
45 ciphersuite: Ciphersuite,
46 group_id: GroupId,
47 epoch: GroupEpoch,
48 tree_hash: VLBytes,
49 confirmed_transcript_hash: VLBytes,
50 extensions: Extensions<Self>,
51}
52
53#[cfg(any(feature = "test-utils", test))]
54impl GroupContext {
55 pub(crate) fn set_epoch(&mut self, epoch: GroupEpoch) {
56 self.epoch = epoch;
57 }
58
59 #[cfg(test)]
61 pub(crate) fn set_ciphersuite(&mut self, ciphersuite: Ciphersuite) {
62 self.ciphersuite = ciphersuite;
63 }
64}
65
66impl GroupContext {
67 pub(crate) fn new(
69 ciphersuite: Ciphersuite,
70 group_id: GroupId,
71 epoch: impl Into<GroupEpoch>,
72 tree_hash: Vec<u8>,
73 confirmed_transcript_hash: Vec<u8>,
74 extensions: Extensions<Self>,
75 ) -> Self {
76 GroupContext {
77 ciphersuite,
78 protocol_version: ProtocolVersion::Mls10,
79 group_id,
80 epoch: epoch.into(),
81 tree_hash: tree_hash.into(),
82 confirmed_transcript_hash: confirmed_transcript_hash.into(),
83 extensions,
84 }
85 }
86
87 #[cfg(feature = "extensions-draft-08")]
88 pub(crate) fn app_data_dict(&self) -> Option<&AppDataDictionary> {
89 self.extensions
90 .app_data_dictionary()
91 .map(|extension| extension.dictionary())
92 }
93
94 pub(crate) fn create_initial_group_context(
96 ciphersuite: Ciphersuite,
97 group_id: GroupId,
98 tree_hash: Vec<u8>,
99 extensions: Extensions<Self>,
100 ) -> Self {
101 Self::new(ciphersuite, group_id, 0, tree_hash, vec![], extensions)
103 }
104
105 pub(crate) fn increment_epoch(&mut self) {
107 self.epoch.increment()
108 }
109
110 pub(crate) fn update_tree_hash(&mut self, new_tree_hash: Vec<u8>) {
112 self.tree_hash = new_tree_hash.into()
113 }
114
115 pub(crate) fn update_confirmed_transcript_hash(
118 &mut self,
119 crypto: &impl OpenMlsCrypto,
120 interim_transcript_hash: &[u8],
121 authenticated_content: &AuthenticatedContent,
122 ) -> Result<(), LibraryError> {
123 let confirmed_transcript_hash = {
124 let input = ConfirmedTranscriptHashInput::try_from(authenticated_content)
125 .map_err(|_| LibraryError::custom("PublicMessage did not contain a commit"))?;
126
127 input.calculate_confirmed_transcript_hash(
128 crypto,
129 self.ciphersuite,
130 interim_transcript_hash,
131 )?
132 };
133
134 self.confirmed_transcript_hash = confirmed_transcript_hash.into();
135
136 Ok(())
137 }
138
139 pub fn protocol_version(&self) -> ProtocolVersion {
141 self.protocol_version
142 }
143
144 pub fn ciphersuite(&self) -> Ciphersuite {
146 self.ciphersuite
147 }
148
149 pub fn group_id(&self) -> &GroupId {
151 &self.group_id
152 }
153
154 pub fn epoch(&self) -> GroupEpoch {
156 self.epoch
157 }
158
159 pub fn tree_hash(&self) -> &[u8] {
161 self.tree_hash.as_slice()
162 }
163
164 pub fn confirmed_transcript_hash(&self) -> &[u8] {
166 self.confirmed_transcript_hash.as_slice()
167 }
168
169 pub(crate) fn set_extensions(&mut self, extensions: Extensions<GroupContext>) {
170 self.extensions = extensions;
171 }
172
173 pub fn extensions(&self) -> &Extensions<GroupContext> {
175 &self.extensions
176 }
177
178 pub fn required_capabilities(&self) -> Option<&RequiredCapabilitiesExtension> {
180 self.extensions.required_capabilities()
181 }
182}