---
Proposed: 2024-09-09
Implemented: ~2025 (SMP v15)
Standardized: 2026-03-10
Protocol: simplex-messaging + agent-protocol
---

> **Implementation note:** This RFC was promoted from done/ to standard/ based on verification that the described feature exists in the codebase. The RFC text reflects the original proposal and may not match the actual implementation in all details. The consolidated protocol specifications in `protocol/` are the authoritative reference for current behavior.

# Blob extensions for SMP queues

Evolution of the design for short links, see [here](./2024-06-21-short-links.md) and [here](./2024-09-05-queue-storage.md).

## Problems

Allow storing extended information with SMP queues to improve UX and security of making connections:
- short invitation links and contact addresses.
- PQ encryption from the first message.
- present user profile with chat preferences and welcome message when the public address link is scanned.

## Design

1. Queue creation/update date is already added to router persistence, allowing to expire queues and blobs, depending on their usage.
2. Add "queue type" metadata to NEW command to indicate whether messaging queue is used as public address or as messaging queue (see previous docs on why it doesn't change threat model). While at the moment it would match sndSecure flag there may be future scenarios when they diverge. Initially only "invitation" and "contact" types will be supported.
3. Prohibit sndSecure flag for "contact" queues, prohibit securing contact queues.
4. Add "queue blobs" to NEW command:
  - blob0: ratchetKeys up to N0 bytes - priority 0, can't be removed by the router, only in "invitation"
  - blob1: PQ key up to N1 bytes - priority 1, can be removed by the router, only used in "invitation"
  - blob2: Application data up to N2 bytes - priority 2, can be removed by the router.
5. Add linkId to NEW command
6. linkId and blobs will be removed when queue is secured.
7. Add recipient command to remove/upsert blob2 for contact queues.
8. Add sender command to retrieve blobs.

## Protocol

### Creating a queue:

The queue owner:
- generates Ed25529 key pair `(sk, spk)` and X25519 key pair `(dhk, dhpk)` to use with the router, same as now. `sk` and `dhk` will be sent in NEW command.
- generates X25519 key pair `(k, pk)` to use with the accepting party to encrypt queue messages.
- derives from `k` using HKDF:
- symmetric key `bk` for authenticated encryption of blobs.
- `linkId`, will be sent in NEW command.
- `k` will be used as short link.
- sends NEW command.

NEW command syntax:

```abnf
create = %s"NEW " linkId queueType recipientAuthPublicKey recipientDhPublicKey
                  basicAuth subscribe sndSecure [ "0" blob0 ] [ "1" blob1 ] [ "2" blob2 ] 
queueType = %s"I" / %s "C" ; new parameter
linkId = length *OCTET ; new parameter,
                        ; can be empty in which case blobs won't be allowed
blob0 = word16 *OCTET ; new parameter, encrypted ratchet keys,
                      ; including nonce and auth tag
blob1 = word16 *OCTET ; new parameter, encrypted PQ key
blob2 = word16 *OCTET ; new parameter, encrypted application data
```

SET - command to update queue blobs (recipientId is used as entity ID):

```abnf
set = %s"SET " linkId [ "2" blob2 ] ; passing empty blob removes it
linkId ; updated (or the same) linkId, can be empty to remove blobs
        ; allows to change the address without removing the queue / changing blobs
        ; (e.g., to avoid losing the messages).
```

### Sending messages to the queue

GET - command to get queue blobs (linkId is used as entity ID):

```abnf
get = %s"GET"
```

Response to GET:

```abnf
blobs = %s"BLOB" senderId [ "0" blob0 ] [ "1" blob1 ] [ "2" blob2 ]
```

As blobs are retrieved using a separate linkId, once blobs are removed it will be impossible to find senderId from short link - it is a threat model improvement. Once router storage is compacted, it will be impossible to find queue related to the link even with the access to router data (unless router preserves the data).

### Possible privacy improvement

We could only allow unauthorized GET and authorized SET commands for long-term "contact" queues, and return BLOB in response to SKEY (or require that GET is authorized) - so that only the person who secures the queue will get access to data blobs. This way it ensures that the parties transmitting the invitation links cannot retrieve their content without the sender noticing it.
