mls_spec/drafts/
split_commit.rs1use crate::{
2 crypto::HpkeCiphertext,
3 defs::{ProtocolVersion, WireFormat},
4 group::commits::ProposalOrRef,
5 messages::{MlsMessage, MlsMessageContent},
6 tree::{UpdatePathNode, leaf_node::LeafNode},
7};
8
9pub const WIRE_FORMAT_MLS_SPLIT_COMMIT: u16 = 0xFFCC; static_assertions::const_assert!(
11 *WireFormat::RESERVED_PRIVATE_USE_RANGE.start() <= WIRE_FORMAT_MLS_SPLIT_COMMIT
12 && WIRE_FORMAT_MLS_SPLIT_COMMIT <= *WireFormat::RESERVED_PRIVATE_USE_RANGE.end()
13);
14
15#[derive(
16 Debug,
17 Clone,
18 PartialEq,
19 Eq,
20 Default,
21 tls_codec::TlsSize,
22 tls_codec::TlsDeserialize,
23 tls_codec::TlsSerialize,
24)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct SplitUpdatePath {
27 pub nodes: Vec<UpdatePathNode>,
28}
29
30#[derive(
31 Debug,
32 Clone,
33 PartialEq,
34 Eq,
35 Default,
36 tls_codec::TlsSize,
37 tls_codec::TlsDeserialize,
38 tls_codec::TlsSerialize,
39)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub struct SplitCommit {
42 #[tls_codec(with = "crate::tlspl::bytes")]
43 pub epoch_identifier: Vec<u8>,
44 pub proposals: Vec<ProposalOrRef>,
45 pub leaf_node: Option<LeafNode>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub struct SplitCommitMessage {
51 pub split_commit_message: Box<MlsMessage>,
52 pub path: Option<SplitUpdatePath>,
53}
54
55impl tls_codec::Size for SplitCommitMessage {
56 fn tls_serialized_len(&self) -> usize {
57 let message_len = matches!(
58 self.split_commit_message.content,
59 MlsMessageContent::MlsPrivateMessage(_) | MlsMessageContent::MlsPublicMessage(_)
60 )
61 .then(|| self.split_commit_message.tls_serialized_len())
62 .unwrap_or_default();
63
64 message_len + self.path.tls_serialized_len()
65 }
66}
67
68impl tls_codec::Serialize for SplitCommitMessage {
69 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
70 if !matches!(
71 self.split_commit_message.content,
72 MlsMessageContent::MlsPrivateMessage(_) | MlsMessageContent::MlsPublicMessage(_),
73 ) {
74 return Err(tls_codec::Error::EncodingError("Cannot serialize a SplitCommitMessage containing other than PrivateMessage or PublicMessage to avoid infinite recursion".into()));
75 }
76
77 let mut written = self.split_commit_message.tls_serialize(writer)?;
78 written += self.path.tls_serialize(writer)?;
79 Ok(written)
80 }
81}
82
83impl tls_codec::Deserialize for SplitCommitMessage {
84 fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error>
85 where
86 Self: Sized,
87 {
88 let version = ProtocolVersion::tls_deserialize(bytes)?;
89 let wire_format = WireFormat::tls_deserialize(bytes)?;
90 let split_commit_message = match *wire_format {
91 WireFormat::MLS_PRIVATE_MESSAGE => MlsMessage { version, content: MlsMessageContent::MlsPrivateMessage(<_>::tls_deserialize(bytes)?) },
92 WireFormat::MLS_PUBLIC_MESSAGE => MlsMessage { version, content: MlsMessageContent::MlsPublicMessage(<_>::tls_deserialize(bytes)?) },
93 _ => return Err(tls_codec::Error::DecodingError("Cannot deserialize a SplitCommitMessage containing other than PrivateMessage or PublicMessage to avoid infinite recursion".into()))
94 };
95
96 Ok(Self {
97 split_commit_message: Box::new(split_commit_message),
98 path: <_>::tls_deserialize(bytes)?,
99 })
100 }
101}
102
103#[derive(
104 Debug,
105 Clone,
106 PartialEq,
107 Eq,
108 tls_codec::TlsSize,
109 tls_codec::TlsDeserialize,
110 tls_codec::TlsSerialize,
111)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
113pub struct PerMemberCommit {
114 pub split_commit_message: MlsMessage,
115 pub encrypted_path_secret: Option<HpkeCiphertext>,
116}