Messaging Mechanics

1-on-1 Lanes & Byte-Borrowing

Send pipelines, optimistic bubbles, failed message refunds, and disjoint keystream borrowing.

Overview

Wiltkey 1-on-1 conversations are structured as a pair of unidirectional lanes sliced out of a single shared keystream.pad file. The initiator of the chat writes outgoing messages to the lower half (offset 0 to size/2) and reads incoming messages from the upper half (offset size/2 to size). The responder writes and reads from the inverse segments.

Because these partitions are rigid, if one user sends significantly more data than the other, their sending lane will deplete (wilt) first, even if the other lane has megabytes of unused capacity. To solve this, Wiltkey implements keystream byte-borrowing, allowing a sender to claim disjoint fragments of the peer's unused sending space.

Keystream Partition Model

Initiator Sending Lane (0 - 5MB) Responder Sending Lane (5MB - 10MB) outgoingOffset outgoingMaxOffset (Ceiling) LENT RANGE

The Send Pipeline

  1. Capacity Check & Offset Allocation: The client checks remaining bytes. If the primary sending lane has insufficient bytes (< 74 bytes), the client scans additionalSlots for a borrowed range. If none exists, it triggers a requestBorrow call and fails the send.
  2. Synchronous Pointer Reservation: To prevent race conditions where a rapid sequence of taps triggers multiple messages consuming the same offset, the client advances the offset pointer synchronously in RAM before starting any async operations.
  3. Optimistic Placeholder Bubble: A message bubble is added instantly to the UI window with isPending = true. The database is not yet touched.
  4. XOR & Socket Transmission: The client ensures the WebSocket is connected, performs the XOR operation on the plaintext bytes, saves the message record to the SQLite DB, and sends a SEND_MESSAGE frame containing the ciphertext envelope over the WebSocket.

Failed Message Refund

When a message send fails (or if the user deletes a pending/failed bubble), Wiltkey recovers the key bytes. If the deleted message's offset matches the tail pointer (i.e. offset + payloadBytes == outgoingOffset), it rolls the pointer back to the message's offset. This prevents gaps in the keystream so that capacity is not permanently lost due to simple connectivity issues.

Byte-Borrowing Mechanics

If a sender's space drops below 500 bytes (proactive top-up) or 74 bytes (hard block), a borrow_request is sent to the peer. The peer divides their own remaining unused sending lane in half:

grant = unused / 2
The peer lowers their sending ceiling (outgoingMaxOffset -= grant) and sends a borrow_grant containing the range [start, end). The borrower registers this as a triple [start, ptr=start, end] in additionalSlots, expanding their sending capacity.

Key Files & Symbols

File Path Symbol Name Description
lib/core/state_chats.dart sendMessage() Handles offset checks, reserves offsets, creates pending bubbles, and transmits envelopes.
lib/core/state_chats.dart clearFailedMessage() Wipes a failed bubble and rolls back pointers to refund keystream.
lib/core/state_borrow.dart AppStateBorrow Extension coordinating byte-borrowing requests, grants, and offset mapping.
lib/core/state_borrow.dart handleBorrowRequest() Calculates grant size, shrinks local outgoing ceiling, and transmits borrow_grant envelope.

Gotchas & Edge Cases

⚠️ NO OUT-OF-ORDER REFUNDS
Refunds only work if the message being cleared is at the head of the sending boundary. If a user deletes an older failed message while newer messages have already advanced the pointer, the refund cannot roll back the pointer (to avoid double-allocation), resulting in a dead hole in the pad.