Skip to content

Wire Format

Cryptid uses a double-encrypted envelope design that provides strong privacy guarantees. This document specifies the wire format — what servers see, what clients see, and how messages are protected.

  1. Server ignorance: Servers learn nothing about message content, type, or participants
  2. End-to-end encryption: Only recipients can decrypt message content
  3. Metadata privacy: Delivery addresses are the only visible routing information

When a message is sent, servers only ever see the outer envelope:

CryptidEnvelope Structure
struct CryptidEnvelope {
// Delivery address for routing
recipient_address: DeliveryAddress,
// Ciphertext encrypted to recipient's public key (not MLS)
encrypted_blob: Vec<u8>,
}
  • recipient_address: Where to deliver the message
  • timestamp: When the server received the message (for ordering)
  • Nothing else: No message type, no sender, no group, no content

Servers cannot:

  • Know what type of message it is (CryptidMessage, SystemOperation, ContactRequest)
  • Know who sent the message
  • Know which group it belongs to
  • Read or modify the message content
  • Correlate messages to specific users or groups
  • Track communication patterns beyond delivery addresses

When the recipient device receives the message, it:

  1. Decrypts the outer layer using its device private key
  2. Extracts the InnerEnvelope
  3. Uses the group_id to route to the correct MLS group
  4. Decrypts the MLS ciphertext to get the actual message
InnerEnvelope Structure
struct InnerEnvelope {
// Sender's device (from MLS authenticated data)
sender_device_id: DeviceId,
// Group ID (None for ContactRequest)
group_id: Option<GroupId>,
// MLS-encrypted message content
mls_ciphertext: Vec<u8>,
}

Handling group_id = None:

When group_id is None, this indicates a ContactRequest (first contact). The client:

  1. Creates a new DirectMessageGroup with deterministic ID (Blake3 of sorted user IDs)
  2. Stores the sender’s UserIdentity in the contact store
  3. Adds the sender’s devices to the new group
  4. Establishes the MLS group state via MLSWelcome

Inside the MLS ciphertext (inside InnerEnvelope), messages are distinguished by the MessageType enum:

MessageType Enum
enum MessageType {
// Application-level messages (user content)
CryptidMessage,
// Protocol/MLS operations (group state changes)
SystemOperation,
// Contact establishment (new contacts/DM groups)
ContactRequest,
}
  • Servers cannot read message content
  • Servers cannot determine message type
  • Server cannot identify sender
  • Server cannot determine group membership
  • Ephemeral delivery addresses prevent long-term tracking
  • Message type and content hidden
  • Fixed-size envelopes possible
  • MLS provides forward secrecy and post compromise security
  • Individual devices can be removed
  • Algorithm: X25519 (ECDH with recipient’s public key)
  • Key: Recipient’s long-term device identity key
  • Purpose: Secure envelope delivery to correct device
  • Who sees: Only recipient device
  • Algorithm: MLS cipher suite (ChaCha20-Poly1305)
  • Key: MLS group key derived from group state
  • Purpose: Group confidentiality and authentication
  • Who sees: All group members
DeliveryAddress Structure
struct DeliveryAddress {
// Address identifier (e.g., "a1b2c3d4e5...")
prefix: String,
// Server domain (e.g., "chat.example.com")
server: String,
// Timestamp of when the address was generated
created_at: u64,
// Can be deactivated without deletion
active: bool,
}
impl DeliveryAddress {
fn full_address(&self) -> String {
format!("{}@{}", self.prefix, self.server)
}
}

The server is intentionally limited:

  • Does NOT store group state
  • Does NOT track message history
  • Does NOT know group membership
  • Does NOT verify message authenticity
  • Does NOT enforce permissions
  • Does NOT validate message content

The server is a dumb pipe: receive blob, deliver blob, forget.

The wire format may evolve to add:

  • Padding: Fixed-size envelopes to prevent traffic analysis
  • Padding schemes: Constant-time padding algorithms
  • Additional metadata: For advanced routing scenarios

Any changes will maintain the core property: servers learn nothing about message content.