1#![forbid(unsafe_code)]
5#![warn(clippy::all, rust_2018_idioms)]
6
7use std::time::Duration;
51use thiserror::Error;
52
53pub mod api;
54pub mod crypto;
55pub mod group;
56pub mod member;
57pub mod protocol;
58pub mod quic_integration;
59
60pub use api::{
61 add_member, group_new, group_new_with_config, recv, remove_member, send, Ciphertext,
62 CommitOptions, GroupId as SimpleGroupId, Identity,
63};
64pub use crypto::{
65 AeadCipher, CipherSuite, CipherSuiteId, Hash, HpkeContext, KeyPair, KeySchedule, MlsAead,
66 MlsHash, MlsKem, MlsSignature,
67};
68pub use group::{GroupConfig, GroupId, GroupState, MlsGroup};
69pub use member::{
70 Credential, CredentialType, GroupMember, KeyPackage, MemberId, MemberIdentity, MemberState,
71 TrustStore,
72};
73pub use protocol::{AuditLogEntry, *};
74
75#[derive(Debug, Error)]
77pub enum MlsError {
78 #[error("Cryptographic operation failed: {0}")]
79 CryptoError(String),
80
81 #[error("Invalid group state: {0}")]
82 InvalidGroupState(String),
83
84 #[error("Member not found: {0:?}")]
85 MemberNotFound(MemberId),
86
87 #[error("Unauthorized operation: {0}")]
88 Unauthorized(String),
89
90 #[error("Protocol error: {0}")]
91 ProtocolError(String),
92
93 #[error("Serialization error: {0}")]
94 SerializationError(String),
95
96 #[error("Key derivation failed: {0}")]
97 KeyDerivationError(String),
98
99 #[error("Message decryption failed")]
100 DecryptionFailed,
101
102 #[error("Invalid epoch: expected {expected}, got {actual}")]
103 InvalidEpoch { expected: u64, actual: u64 },
104
105 #[error("`TreeKEM` operation failed: {0}")]
106 TreeKemError(String),
107
108 #[error("Invalid message: {0}")]
109 InvalidMessage(String),
110
111 #[error("Deserialization error: {0}")]
112 DeserializationError(String),
113
114 #[error("IO error: {0}")]
115 Io(#[from] std::io::Error),
116}
117
118pub type Result<T> = std::result::Result<T, MlsError>;
119
120pub const MLS_VERSION: u16 = 1;
122
123pub const MAX_GROUP_SIZE: usize = 65536; pub const DEFAULT_KEY_ROTATION_INTERVAL: Duration = Duration::from_secs(24 * 3600); pub type MessageSequence = u64;
131
132pub type EpochNumber = u64;
134
135#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
137pub struct WireFormat {
138 pub version: u16,
139 pub extensions: Vec<u16>,
140}
141
142impl Default for WireFormat {
143 fn default() -> Self {
144 Self {
145 version: MLS_VERSION,
146 extensions: Vec::new(),
147 }
148 }
149}
150
151#[derive(Debug, Clone)]
153pub struct MlsConfig {
154 pub max_group_size: usize,
156 pub key_rotation_interval: Duration,
158 pub enable_pcs: bool,
160 pub enable_fs: bool,
162 pub cipher_suite: CipherSuite,
164 pub max_message_age: Duration,
166}
167
168impl Default for MlsConfig {
169 fn default() -> Self {
170 Self {
171 max_group_size: MAX_GROUP_SIZE,
172 key_rotation_interval: DEFAULT_KEY_ROTATION_INTERVAL,
173 enable_pcs: true,
174 enable_fs: true,
175 cipher_suite: CipherSuite::default(),
176 max_message_age: Duration::from_secs(300), }
178 }
179}
180
181#[derive(Debug, Clone, Default)]
183pub struct MlsStats {
184 pub groups_active: usize,
185 pub messages_sent: u64,
186 pub messages_received: u64,
187 pub key_rotations: u64,
188 pub member_additions: u64,
189 pub member_removals: u64,
190 pub epoch_transitions: u64,
191}
192
193#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_mls_config_defaults() {
201 let config = MlsConfig::default();
202 assert_eq!(config.max_group_size, MAX_GROUP_SIZE);
203 assert_eq!(config.key_rotation_interval, DEFAULT_KEY_ROTATION_INTERVAL);
204 assert!(config.enable_pcs);
205 assert!(config.enable_fs);
206 }
207
208 #[test]
209 fn test_wire_format_default() {
210 let format = WireFormat::default();
211 assert_eq!(format.version, MLS_VERSION);
212 assert!(format.extensions.is_empty());
213 }
214
215 #[test]
216 fn test_mls_stats_default() {
217 let stats = MlsStats::default();
218 assert_eq!(stats.groups_active, 0);
219 assert_eq!(stats.messages_sent, 0);
220 assert_eq!(stats.messages_received, 0);
221 }
222}