1use serde::{Deserialize, Serialize};
4
5use crate::{clock::Hlc, conversation::ConversationId, device::DeviceId, WIRE_VERSION};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[repr(u8)]
10pub enum MessageKind {
11 Application = 1,
12 Commit = 2,
13 Welcome = 3,
14 Proposal = 4,
15 KeyPackage = 5,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct MessageEnvelope {
21 pub v: u8,
22 pub conversation_id: ConversationId,
23 pub epoch: u64,
24 pub kind: MessageKind,
25 pub sender_device: DeviceId,
26 pub seq: u64,
27 pub hlc: Hlc,
28 #[serde(with = "serde_bytes")]
29 pub payload: Vec<u8>,
30 pub content_hash: [u8; 32],
31}
32
33impl MessageEnvelope {
34 pub fn new(
42 conversation_id: ConversationId,
43 epoch: u64,
44 kind: MessageKind,
45 sender_device: DeviceId,
46 seq: u64,
47 hlc: Hlc,
48 payload: Vec<u8>,
49 ) -> Self {
50 debug_assert!(
51 !matches!(kind, MessageKind::Application),
52 "use MessageEnvelope::new_application for Application kind (CR-6 hashes plaintext)"
53 );
54 let content_hash = hash_handshake(kind, &payload);
55 Self {
56 v: WIRE_VERSION,
57 conversation_id,
58 epoch,
59 kind,
60 sender_device,
61 seq,
62 hlc,
63 payload,
64 content_hash,
65 }
66 }
67
68 pub fn new_application(
80 conversation_id: ConversationId,
81 epoch: u64,
82 sender_device: DeviceId,
83 seq: u64,
84 hlc: Hlc,
85 payload: Vec<u8>,
86 plaintext: &[u8],
87 ) -> Self {
88 let content_hash = hash_application_plaintext(plaintext);
89 Self {
90 v: WIRE_VERSION,
91 conversation_id,
92 epoch,
93 kind: MessageKind::Application,
94 sender_device,
95 seq,
96 hlc,
97 payload,
98 content_hash,
99 }
100 }
101}
102
103pub fn hash_handshake(kind: MessageKind, payload: &[u8]) -> [u8; 32] {
106 use sha2::{Digest, Sha256};
107 let mut h = Sha256::new();
108 h.update([kind as u8]);
109 h.update(payload);
110 h.finalize().into()
111}
112
113pub fn hash_application_plaintext(plaintext: &[u8]) -> [u8; 32] {
117 use sha2::{Digest, Sha256};
118 let mut h = Sha256::new();
119 h.update(plaintext);
120 h.finalize().into()
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct IncomingMessage {
126 pub conversation_id: ConversationId,
127 pub sender_device: DeviceId,
128 pub epoch: u64,
129 pub hlc: Hlc,
130 #[serde(with = "serde_bytes")]
132 pub plaintext: Vec<u8>,
133 pub content_hash: [u8; 32],
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct OutgoingMessage {
139 #[serde(with = "serde_bytes")]
141 pub plaintext: Vec<u8>,
142}