Messaging
Message lifecycle from compose to display, with privacy at every step.
Message Lifecycle
COMPOSE → SERIALIZE → COMPRESS → ENCRYPT → SEAL → PAD → BATCH → ROUTE → DELIVER
|
DISPLAY ← STORE ← DECOMPRESS ← DECRYPT ← VERIFY ← UNSEAL ← UNPAD ← RECEIVE
Compose
The user types a message in the UI. The message is held in application memory as a UTF-8 string. No data is written to disk until the message is encrypted and stored in the local database.
Serialize
Message protobuf schema:
message RvntMessage {
bytes id = 1; // UUID v4 (16 bytes)
uint64 timestamp = 2; // Unix epoch milliseconds
string content = 3; // UTF-8 text body
bytes reply_to = 4; // Optional: UUID of quoted message
uint32 flags = 5; // Bit flags (see below)
repeated Attachment attachments = 6;
}
message Attachment {
bytes hash = 1; // BLAKE3 hash of original file (32 bytes)
string filename = 2; // Original filename
string mime_type = 3; // MIME type
uint64 size = 4; // File size in bytes
bytes thumbnail = 5; // Optional: encrypted thumbnail
bytes key = 6; // Per-file encryption key (32 bytes)
}
Message flags (bit field):
0x01 EPHEMERAL Message auto-deletes after read
0x02 PRIORITY High-priority (push notification)
0x04 SILENT No notification on receipt
0x08 EDIT This message edits a previous message (reply_to = original)
0x10 DELETE This message deletes a previous message (reply_to = target) Compress, Encrypt, Seal, Pad, Route
See How It Works for the detailed pipeline. The serialized protobuf is compressed (zstd), encrypted (Double Ratchet / AES-256-GCM), wrapped in a sealed sender envelope, padded to a fixed size, optionally batched (mixnet), and routed through Tor.
Message Status System
RVNT tracks message status through a state machine. Each transition generates a status update that is sent back through the same encrypted pipeline.
Message status state machine:
QUEUED → SENT → DELIVERED → READ
│ │ │
│ │ └── Recipient opened conversation
│ └── Recipient device received envelope
└── Message encrypted and queued for transmission
Error states:
QUEUED → FAILED (network error, peer offline)
SENT → EXPIRED (no delivery acknowledgment within 24h)
Status transitions:
QUEUED: Message encrypted, added to outbound queue
SENT: Tor circuit confirmed transmission to peer's address
DELIVERED: Recipient device sent encrypted ACK
READ: Recipient opened the conversation containing this message
FAILED: Transmission failed after retry attempts exhausted
EXPIRED: No delivery ACK received within TTL (default 24 hours) Delivery Acknowledgments
When a recipient's device receives and successfully decrypts a message,
it sends a delivery acknowledgment back to the sender:
DeliveryAck {
message_id: UUID of acknowledged message [16 bytes]
status: DELIVERED (0x01) or READ (0x02) [1 byte]
timestamp: When the status changed [8 bytes]
}
The ACK is:
1. Encrypted with the same Double Ratchet session
2. Wrapped in a sealed sender envelope
3. Routed through Tor
4. Indistinguishable from a regular message to an observer
The ACK does NOT reveal:
- Which message was acknowledged (encrypted)
- Who sent the ACK (sealed sender)
- That it IS an ACK vs a regular message (same format + padding) Typing Indicators
Typing indicators tell your contact that you are currently composing a message. This is a convenience feature with privacy implications.
Typing indicator behavior:
- Sent when user begins typing (debounced: 3 seconds)
- Sent when user stops typing (after 5 seconds of inactivity)
- NOT sent for every keystroke
- Rate limited: maximum 1 typing event per 3 seconds
TypingIndicator {
action: START (0x01) or STOP (0x02) [1 byte]
}
Privacy options:
- Global disable: Settings > Privacy > Typing Indicators > Off
- Per-conversation disable: Conversation settings > Typing > Off
- Disabling typing indicators also stops receiving them
(reciprocal: if you don't send, you don't receive)
Security note:
Typing indicators are encrypted and sealed like regular messages.
An observer cannot distinguish a typing indicator from a message.
However, the timing pattern of typing indicators can reveal
conversation activity patterns. Disable if this is a concern. Online Status
RVNT can show whether a contact is currently online. This feature is opt-in and disabled by default.
Online status modes:
OFF (default): Your online status is never shared
CONTACTS: Only mutual contacts see your status
EVERYONE: Any RVNT user can see your status
Implementation:
- Presence is communicated via the libp2p gossipsub protocol
- Encrypted presence announcements to subscribed contacts
- No server stores online status
- Status is ephemeral: 60-second TTL, must be refreshed
Privacy considerations:
- Online status reveals when you are using RVNT
- This can be used to build activity patterns
- Disabled by default for this reason
- Even when enabled, status is only visible to selected contacts Read Receipts
Read receipts tell the sender that the recipient has opened the conversation and presumably read the message.
Read receipt behavior:
- Triggered when the recipient opens a conversation with unread messages
- NOT triggered for individual messages (batch: all unread marked as read)
- Sent as a READ status update (same as delivery ACK format)
Privacy options:
- Global disable: Settings > Privacy > Read Receipts > Off
- Per-conversation disable: Conversation settings > Read Receipts > Off
- Reciprocal: disabling read receipts also prevents you from seeing
whether your contacts have read your messages
Default: ENABLED (can be changed during onboarding) Ephemeral Messages
Ephemeral messages auto-delete after being read. The deletion is local: the message is removed from the recipient's database after a configurable timer.
Ephemeral message timers:
5 seconds (view once)
30 seconds
5 minutes
1 hour
24 hours
7 days
Implementation:
1. Sender sets EPHEMERAL flag + timer duration
2. Message is sent through normal pipeline
3. Recipient decrypts and displays message
4. Timer starts when message is displayed on screen
5. When timer expires:
a. Message deleted from SQLCipher database
b. Any associated media deleted from cache
c. Thumbnail removed
d. Deletion is irreversible
6. Sender receives a DELETED status update
Limitations:
- The recipient can screenshot before the timer expires
- The recipient can photograph the screen
- RVNT does NOT attempt screenshot detection (unreliable)
- Ephemeral messages are a usability feature, not a security guarantee Message Editing and Deletion
Edit:
- Send a new message with EDIT flag set
- reply_to field contains the UUID of the original message
- Recipient's UI replaces the original message content
- Edit history is stored locally (recipient can view edits)
- Edits are encrypted the same as regular messages
Delete (for everyone):
- Send a new message with DELETE flag set
- reply_to field contains the UUID of the message to delete
- Recipient's UI removes the message
- A "message deleted" placeholder may be shown
- The actual ciphertext is deleted from the recipient's database
- Works within 24 hours of original send (after that, local-only delete) Further Reading
- How It Works -- Full encryption pipeline
- File Transfer -- Sending files and media
- Double Ratchet -- How each message gets its own encryption key