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 = 0xFFCC; // 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
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}