MLS Protocol Usage
Overview
Conclave uses the Messaging Layer Security (MLS) protocol (RFC 9420) for all end-to-end encryption. Every conversation — whether between two people or a large group — is an MLS group. There is no separate direct messaging protocol.
The server acts as a delivery service (as defined in RFC 9420 Section 3): it stores and forwards opaque MLS messages without interpreting their contents. All cryptographic operations (key generation, encryption, decryption, group state management) are performed exclusively on the client.
Cipher Suite
Conclave uses MLS cipher suite CURVE448_CHACHA (cipher suite ID 6 as defined in RFC 9420 Section 17.1):
| Component | Algorithm |
|---|---|
| Key Exchange (KEM) | X448 |
| Authenticated Encryption (AEAD) | ChaCha20-Poly1305 |
| Hash | SHA-512 |
| Signature | Ed448 |
| Security Level | 256-bit |
All clients and servers in a Conclave deployment MUST support this cipher suite. All groups MUST use this cipher suite.
Sync Mode
MLS operations are CPU-bound cryptographic computations. The MLS library runs in synchronous mode on the client. Client implementations that use asynchronous runtimes (e.g., tokio, async-std) SHOULD offload MLS operations to a blocking task pool to avoid stalling the event loop.
Epoch Retention
MLS groups advance through epochs on each commit (member add, member remove, key rotation, external rejoin). Clients need to retain key material from prior epochs to decrypt messages that were encrypted under those epochs.
Clients SHOULD retain key material for at least 16 prior epochs. This allows a client to be offline through up to 16 group state transitions (commits) and still decrypt messages sent during those epochs.
Regular application messages (chat) do not advance the epoch. A client can be offline through an unlimited number of chat messages within the same epoch.
Decryption Error Handling
When a client fails to decrypt a message (e.g., because the epoch’s key material has been evicted), the client SHOULD:
- Display a warning to the user indicating the message could not be decrypted, including the message’s sequence number and the reason for failure.
- Advance the sequence tracking past the undecryptable message. Failed messages cannot be retried — blocking on them would cause infinite retry loops.
- Continue processing subsequent messages.
If a user experiences persistent decryption failures, they can perform an account reset to rejoin the group with fresh cryptographic state.
MLS Operations Summary
The following MLS operations are used in Conclave:
| Operation | MLS Primitive | Conclave Usage |
|---|---|---|
| Generate signing identity | signature_key_generate() | Registration, account reset |
| Generate key package | generate_key_package_message() | Pre-publishing credentials |
| Create group | create_group() + commit_builder().build() | New group creation |
| Invite member | commit_builder().add_member(key_package).build() | Adding members to groups |
| Join group | join_group(welcome_message) | Processing a Welcome after invite acceptance |
| Encrypt message | encrypt_application_message(plaintext) | Sending chat messages |
| Decrypt message | process_incoming_message(ciphertext) | Receiving chat messages and commits |
| Remove member | commit_builder().remove_member(index).build() | Kicking a member |
| Leave group | commit_builder().remove_member(own_index).build() | Voluntary departure |
| Rotate keys | commit_builder().build() (empty commit) | Forward secrecy, phantom leaf cleanup |
| External rejoin | external_commit_builder().build(group_info) | Account reset rejoin |
| Export GroupInfo | group_info_message_allowing_ext_commit(true) | Enabling external commits |