Skip to main content

mls_spec/drafts/
split_commit.rs

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