From 7d9c2adcdd11a833e9fa4bb1bdee7ee94d3a0ce7 Mon Sep 17 00:00:00 2001 From: epoberezkin Date: Thu, 30 Apr 2026 18:33:51 +0000 Subject: [PATCH] deploy: 6b6f4945025e9a958da69bf9a8d7db9117a982ba --- docs/protocol/channels-overview.html | 1298 ++++++++++++++++++++++++++ docs/protocol/channels-protocol.html | 1201 ++++++++++++++++++++++++ docs/protocol/simplex-chat.html | 40 +- 3 files changed, 2537 insertions(+), 2 deletions(-) create mode 100644 docs/protocol/channels-overview.html create mode 100644 docs/protocol/channels-protocol.html diff --git a/docs/protocol/channels-overview.html b/docs/protocol/channels-overview.html new file mode 100644 index 0000000000..c9d0fad7fc --- /dev/null +++ b/docs/protocol/channels-overview.html @@ -0,0 +1,1298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + +
+
+
+ +
+ + + + +

Revision 1, 2026-04-28

+

SimpleX Channels: stateful information delivery and management

+

Table of contents

+ +

Introduction

+

The SimpleX network provides private point-to-point communication without user or endpoint identifiers, but most speech that matters is public. Every existing platform that distributes content at scale identifies both publishers and their audiences to the operator - none protect participation privacy. SimpleX Chat supported peer-to-peer groups, but they cannot scale to large audiences. SimpleX Channels close this gap.

+

What are SimpleX Channels

+

SimpleX Channels are a stateful information delivery and management layer built on the SimpleX network. SMP queues provide stateless, unidirectional packet delivery between two endpoints. Channels add persistence, state, and scalable distribution - enabling one-to-many publishing with cryptographic identity independent of infrastructure operators.

+

SimpleX Chat is the first application, presenting channels as a broadcast publication model where owners publish and subscribers read, react, and comment. But channels are not limited to this use case - they are a general-purpose layer for distributing and managing stateful information (feeds, telemetry, automated pipelines, coordination services, social media). This document describes channels as a transport mechanism - the same mechanism will also be used for large groups, communities, wikis, forums, and other social media primitives.

+

The critical difference from conventional publish-subscribe systems is that channel identity and governance are controlled cryptographically by the channel owners, not by the infrastructure operators. Relays - SimpleX network clients that forward and optionally cache channel content - can be added, removed, and replaced without changing the channel's identity, address, content, or cryptographic trust chain. A channel's relationship with its relays is transient; its identity is permanent. The authoritative record of content is hosted on channel owners' devices; relays perform transmission and caching similar to CDN infrastructure.

+

Channel owners hold full control of the channel - its identity, content, governance rules, and membership - through self-custody of cryptographic keys. No infrastructure operator, relay provider, or third party can control or alter a channel without the owner's keys. Blockchain systems achieve a related property for financial assets - no third party can control holdings - through network-wide consensus. Channels achieve it through local authority and cryptographic signatures, without global consensus or a public ledger. Unlike blockchain state, channel state is mutable by the owner and not publicly verifiable by third parties.

+

Channels as transport layer

+

The SimpleX network has three transport layers, each built on the one below:

+
    +
  1. +

    SMP (SimpleX Messaging Protocol) - stateless, unidirectional packet delivery between two endpoints through SMP routers. Provides fixed-size blocks, 2-node onion routing, and transport metadata protection.

    +
  2. +
  3. +

    SimpleX agents (agent protocol) - bidirectional, redundant connections between endpoints, with end-to-end post-quantum double ratchet encryption. The SimpleX Chat Protocol runs on top of this layer, providing direct messaging, group communication, and metadata delivery for file transfers via XFTP protocol.

    +
  4. +
  5. +

    Channels - stateful, one-to-many information delivery and management with cryptographic ownership and programmable governance. This layer runs on top of chat and agent layer 2, and it is described in this document.

    +
  6. +
+

No network-wide user profile identifiers exist at any of these layers. Just as SMP enables private messaging by providing transport without user identifiers, channels enable public communication while preserving participation privacy at the distribution layer.

+

Channel relays are themselves SimpleX clients in the SMP network, connecting to SMP routers using the same protocol, the same 2-node onion routing, and the same fixed-size transport blocks as any other endpoint. Even though the SMP network can distinguish a relay from a person's phone by its transport patterns, it prevents relays from learning anything about other network endpoints. In the case of SimpleX Chat, any CLI client can act as a chat relay without modifications.

+

Channels therefore inherit all of SMP's transport privacy properties:

+
    +
  • +

    Relays cannot observe subscriber network addresses. The relay sees SMP queue addresses, not IP addresses or network sessions. The subscriber's IP is known only to their SMP router, which cannot see the message content (encrypted at the agent layer) or the IP addresses of whoever sends messages.

    +
  • +
  • +

    SMP routers cannot see channel content. Messages between relay and subscriber are end-to-end encrypted. The SMP router forwards fixed-size encrypted blocks without knowing whether they carry channel messages, direct messages, or anything else.

    +
  • +
  • +

    Participation in multiple channels is unlinkable. Each channel connection uses independent SMP queues with separate cryptographic credentials. Because of packet-level anonymity in 2-node routing, even if a subscriber uses the same SMP routers for all channels, the sending relays cannot determine this without collusion with those routers. Clients choose independently operated routers by default.

    +
  • +
+

No single point in the system sees both content and network identity. SMP routers see network addresses but not content, and no single SMP router can see which endpoints are communicating because clients choose independently operated routers. Relays see content but not network addresses.

+

Content visibility and participant privacy

+

Any channel joinable via a public link, whether encrypted or not, must be considered completely public - the cost of joining through automated means has collapsed with large language models and is approaching zero. End-to-end encrypting such content provides no privacy; it only undermines users' security by creating false expectations and increases infrastructure operators' risks by making them unable to see what they deliver. Private channels with encrypted content are a separate use case discussed in Future work.

+

Content of public channels is therefore not end-to-end encrypted between owner and subscriber. Relays can read the messages they forward. Relay operators cannot undetectably alter channel content when multiple relays serve the channel, and cannot alter signed content at all - the authoritative state is held by owners. That each channel can use multiple chat relays provides both technical reliability and censorship resistance against any relay-specific content policies.

+

The achievable privacy property for public communication is participation privacy - protecting who reads and writes content. The SMP transport carries no user identifiers, and relays are ordinary SMP clients, so subscribers connect without revealing their identity, network address, or any information that persists across channels. If an adversary joins a SimpleX channel, they see everything that is sent, but cannot determine who sent it or link any participant to anything outside the channel.

+

Other systems make the opposite choice: content encryption in exchange for participant identification. For groups and channels joinable via public links this is the opposite of what is needed - the content encryption is meaningless (anyone can join and read), while the participant identification is the security threat.

+

In comparison

+

Telegram channels - the operator controls channel identity (usernames are revocable), has full access to both content and participant identity. Channels cannot exist without Telegram's permission.

+

Nostr relays - a single persistent key is used for publishing, following, and identity. Relays see content, the user's key, and their IP address. All posts and follow lists are signed and non-repudiable, linked to the same key - making both publishing and reading activity traceable and undeniable.

+

Signal groups - content is end-to-end encrypted, but the operator manages group state and can observe the membership graph. Groups are capped at 1,000 members with no concept of a channel.

+

Matrix rooms - server operators see room membership and metadata. Room identity is bound to the creating server's domain - if the server disappears, the room identity is lost.

+

Mastodon / ActivityPub - publisher identity is bound to a server domain - if the server disappears, the identity is lost. Server operators see all content and all follower relationships. No encryption or privacy of any kind.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTelegramNostrSignalMatrixMastodonSimpleX
Content visible to operatorYesYesNoConfigurableYesYes
Participant identity visible to operatorYesYesYesYesYesNo
Channel identity independent of infrastructureNoYesNoNoNoYes
Sovereign ownership (no 3rd party can seize)NoYesNoNoNoYes
Programmable governanceNoNoNoNoNoPlanned
Cryptographic content deniabilityNoNoYesYesNoYes (default)
Scalable one-to-many deliveryYesYesNoLimitedYesYes
+

Non-goals

+

Channels do not attempt to:

+
    +
  • Encrypt public content from relay operators. See Content visibility and participant privacy.
  • +
  • Assign persistent identities to participants. There are no usernames, public keys, or any identifiers that persist across channels or link activity across contexts.
  • +
  • Require network-wide consensus. Channel state is authoritative on owner devices. The network does not validate channel transactions.
  • +
  • Guarantee immutability of content. Channel state is fully controlled and mutable by owners, unlike blockchain state, which is immutable by design.
  • +
+

Architecture

+

The introduction established what channels provide and why. This section describes how: where state lives, how identity and ownership work, how governance evolves, and what each participant does.

+

State and distribution

+

The authoritative record of a channel - content, member roster, profile, cryptographic keys, governance rules - is held by channel owners on their own devices, not on relays, not on any server, and not on any shared ledger. Relays hold transient copies for distribution and optional caching, analogous to CDN edge nodes: the origin holds the truth, CDN nodes come and go. Consensus is only required between channel owners, not across the entire network.

+
                     ┌──────────┐
+                     │  Owner   │  <- authoritative state
+                     └────┬─────┘
+                          │
+              ┌───────────┼───────────┐
+              │           │           │
+         ┌────▼───┐  ┌────▼───┐  ┌────▼───┐
+         │Relay A │  │Relay B │  │Relay C │  <- cache / distribution
+         └────┬───┘  └────┬───┘  └────┬───┘
+              │           │           │
+        ┌─────┼─────┐    ...    ┌─────┼─────┐
+        │     │     │           │     │     │
+       S1    S2    S3          S7    S8    S9   <- received copies
+
+

Content originates on the owner's device and flows through relays to subscribers. Each relay independently forwards to all of its subscribers. Subscribers do not connect to owners or to each other - this provides better scalability than peer-to-peer SimpleX groups, where adding a member requires N new connections. When multiple relays serve the same channel, subscribers deduplicate at the client level.

+

Failure modes:

+
    +
  • +

    Loss of a relay is loss of a cache node, not loss of data. The owner can send the same content through a replacement relay.

    +
  • +
  • +

    Loss of all owner devices is the catastrophic event - relay caches become orphaned and the channel's private keys are gone. Multiple owners and backups mitigate this risk.

    +
  • +
  • +

    Disagreements between relays are resolved by the origin. The owner's version is authoritative, settling cache inconsistency through any reachable relay.

    +
  • +
+

Subscribers hold their own received copies. Signed messages are independently verifiable without consulting the relay or owner. Unsigned content depends on cross-relay consistency or future transcript integrity mechanisms.

+

Identity and ownership

+

A channel's identity is the SHA-256 hash of the genesis root public key, computed at creation time and never changed - even if relays are added, removed, or the channel link is rotated. It is self-authenticating: derived from a key pair that only the channel creator held. It is embedded in the channel's link, distributed in the profile to all members, and used as a binding prefix in all signed messages.

+

Subscribers validate that the identity in the link matches the identity in the profile, preventing link substitution. Profile updates that attempt to change the identity are rejected. Full validation that the identity equals the hash of the root key is deferred: if current clients enforced this check, they would reject future rotated links as invalid. The identity is correctly managed today; validation will be enforced with the key rotation protocol. See the group identity binding RFC.

+

The root key does not sign messages directly. Instead, it authorizes owner keys through a signed chain. At creation, the owner generates a root key pair and a separate member key pair for signing. The member key is published as an authorization entry signed by the root key. New owners can be added by any previously authorized owner signing a new entry. Anyone retrieving the channel link can verify this chain without network access.

+

The root key is a bootstrap key - it certifies owners, then need not be used again. All owners are cryptographically indistinguishable to subscribers (they all have equally valid authorization chains), which - provided multiple owners were signed by the root key - conceals the creator's identity.

+

The channel link is the out-of-band trust anchor - relays and SMP routers cannot modify link content. All members announce their signing keys on joining. Owner keys are verifiable against the link. Role changes (promoting members to admin, moderator) are signed by owners at the protocol level.

+

A planned extension will record role changes as a linearly ordered signed roster log with consistent sequencing across all owners, relays, and subscribers. This linearization prevents ambiguous roster states from concurrent unordered changes, and creates a verifiable chain of trust from the channel link through owners to all elevated roles. Out-of-band key verification for non-owner members will further extend this to E2E encrypted conversations.

+

Governance

+

"Management" in "information delivery and management" refers not only to managing content but to managing the channel itself - who can make decisions, and how.

+

The low-level protocol supports multiple owners from the initial release. The application-level governance model evolves through a planned progression:

+

Current (v6.5): Single owner. One owner controls the channel. All administrative actions (profile changes, roster modifications, relay management) are decided by this single owner. The protocol-level owners chain supports verification of multiple entries, but the application creates and manages only one.

+

Near-term (v7): Multiple owners, any-owner-decides. Multiple owners share control of the channel. Any owner can independently make any administrative decision - add or remove members, change the profile, manage relays. This is the most common decision-making model in practice (equivalent to "all admins are equal" in most online platforms). No coordination between owners is required for any action.

+

Future: Multisig and programmable governance. Further stages include M-of-N multisig for administrative actions and, eventually, programmable governance rules defined as code in the channel's definition. The protocol must support these without prescribing a specific governance model.

+

Roles

+
    +
  • +

    Owners create the channel, hold the authoritative state and private keys on their devices, publish content, and manage the member roster. Owners sign administrative messages and optionally content messages. A channel must have at least one owner.

    +
  • +
  • +

    Relays receive content from owners and members with posting rights, optionally cache it, and forward it to subscribers. They accept new subscriber connections and introduce them to the channel owners. Relays cannot author messages. A channel must have at least one active relay. Relays are ordinary SimpleX clients - a relay can be operated by anyone (a channel operator, a third-party service provider, or a self-hosted instance) and each creates its own contact address link, bound to the channel's identity. The relay's relationship with the channel is transient - owners can add and remove relays without changing the channel's identity.

    +
  • +
  • +

    Subscribers connect to relays and receive content. They cannot send messages by default, but can be given posting rights.

    +
  • +
+

Additional roles (moderator, admin, member, author) exist in the hierarchy and are inherited from the group protocol.

+

For protocol-level detail - wire formats, message types, signing and verification mechanics, delivery pipeline - see SimpleX Channels Protocol.

+

Cryptographic primitives

+
    +
  • +

    Ed25519 - channel identity (root key pair), owner authorization chain, and message signing. The signature binding prefix includes the channel's entity ID and the sender's member ID, preventing cross-channel replay.

    +
  • +
  • +

    SHA-256 - derives the channel's entity ID from the genesis root public key. Immutable, serves as the channel's permanent identity.

    +
  • +
  • +

    Double ratchet with post-quantum KEM (inherited from SimpleX agent layer) - end-to-end encryption for all SMP transport. Not channel-specific - channels inherit it by being built on the agent layer. Future E2E side conversations (support scope, member DMs, private channels) will use the same mechanism.

    +
  • +
+

Content messages are not signed by default to preserve cryptographic deniability - see Signing scope. Owners may opt into signing all content in a future release.

+

Security

+

This section examines what the architectural properties protect against, where they hold, and where gaps remain.

+

Design objectives

+

The channel protocol is designed to achieve the following security objectives:

+
    +
  1. Stable message delivery between channel participants, resilient to individual relay failures.
  2. +
  3. No possibility for a relay to substitute the channel - the channel's identity is cryptographically bound to the link and profile controlled by channel owners.
  4. +
  5. No possibility for a relay to impersonate an owner - administrative messages require valid signatures.
  6. +
  7. Prevention of relay-initiated roster manipulation - member removal, role changes, and other roster modifications require valid owner signatures.
  8. +
  9. Relay transience - the owner can add and remove relays, including the last relay, without permanently losing the channel. Subscribers can restore connectivity by retrieving updated link data.
  10. +
  11. Sender anonymity within multi-owner channels - owners can publish as the channel, hiding which specific owner authored a message from subscribers.
  12. +
  13. Participant privacy - relay operators cannot determine subscriber identity or network address, and subscribers cannot determine each other's identity. This is inherited from the SMP transport layer.
  14. +
+

Signing scope: roster only, content optional

+

By default, only roster-modifying and administrative messages are signed. Content messages are not signed. Two reasons:

+
    +
  1. +

    Cryptographic deniability. Signing creates non-repudiable proof of authorship verifiable by any third party. Without signatures, no such proof exists - a relay could have fabricated any unsigned message.

    +
  2. +
  3. +

    Proportional defense. Changes to roster, channel profile, and permissions can be disruptive and irreversible - they must be authenticated at processing time. Content manipulation is detectable post-hoc through cross-relay consistency, and the authoritative record on the owner's device is unaffected.

    +
  4. +
+

Owners will be able to opt into signing content on a per-channel or per-message basis - some publishers want non-repudiable authorship, others prefer deniability.

+

Threat model

+

This threat model assumes the SimpleX network threat model and addresses threats specific to the channel layer.

+

A single compromised relay

+

can:

+
    +
  • Substitute unsigned content or selectively drop messages for its subscribers. Detectable by subscribers connected to other relays - the owner's version is authoritative. TODO: difference detection not yet implemented.
  • +
  • Selectively target specific subscribers while delivering correctly to others.
  • +
  • Ignore the "message from channel" directive, revealing which owner sent a message. Detectable out-of-band.
  • +
  • Fabricate or hide subscriber connections, inflating or deflating counts. Detectable if subscribers are connected to other relays.
  • +
+

cannot:

+
    +
  • Undetectably substitute content - subscribers on honest relays receive the original.
  • +
  • Alter the channel's authoritative state on the owner's device.
  • +
  • Substitute the channel profile or impersonate an owner - these require valid signatures.
  • +
  • Redirect subscribers to a different channel - the entity ID is validated across link and profile.
  • +
  • Determine subscriber identity or network address - inherited from SMP transport.
  • +
  • Correlate subscriber participation across channels - each connection uses independent SMP queues. The subscriber chooses their SMP router independently, so collusion between a relay and the relay's SMP router does not compromise connections through a different router.
  • +
+

All relays compromised and colluding

+

can:

+
    +
  • Undetectably substitute unsigned content for all subscribers, unless owners sign content messages.
  • +
  • Prevent delivery of any messages, including signed ones (signing prevents substitution, not dropping).
  • +
  • Fabricate or hide subscriber connections undetectably.
  • +
+

cannot:

+
    +
  • Forge signed administrative messages or substitute the channel profile.
  • +
  • Alter the authoritative state on the owner's device.
  • +
+

Compromise of owner keys

+

An attacker who obtains the root private key or an owner's member private key (through device compromise, backup theft, or coercion) can impersonate the owner and sign arbitrary administrative messages. This is a different threat from key loss - the channel continues operating, but under adversarial control. Mitigation depends on owner-side operational security and future multisig governance. For the threat model of the channel link itself (the trust anchor), see the short links for groups RFC.

+

Loss of all owner devices

+

The channel can have no new content, no administrative updates, no new owners. Relay caches continue delivering existing content but cannot be refreshed, and will eventually expire in the absence of the owner connection. Multiple owners and key backups mitigate this risk.

+

A subscriber

+

can:

+
    +
  • See all public content, by design.
  • +
  • Join multiple times with different profiles, inflating counts.
  • +
+

cannot:

+
    +
  • Identify other subscribers, send messages to the channel (unless given posting rights), or forge messages of the owner or other subscribers.
  • +
+

A passive network observer

+

can:

+
    +
  • Observe communication with an SMP router, but not whether it is channel-related.
  • +
+

cannot:

+
    +
  • Determine which channel a subscriber uses, correlate channel activity with other SimpleX activity, or identify a relay as distinct from an ordinary user, other than by traffic volume. Inherited from SMP transport.
  • +
+

Current gaps

+
    +
  1. Cross-relay consistency detection. Duplicate messages are silently deduplicated without hash comparison. Designed but not implemented.
  2. +
  3. Link entity ID validation. Deferred to a future version with key rotation. See group identity binding RFC.
  4. +
  5. Multi-relay UX. Protocol supports multiple relays per subscriber; no UX for monitoring relay-level delivery health. It will be added in v6.5.x.
  6. +
+

Future work

+

Stateful access and history navigation

+

Currently, relays send recent cached history on join but do not support navigation or search. Planned: history pagination by timestamp or message ID, remote search against relay caches, and selective retrieval of specific message ranges. Relay operators can differentiate on cache depth and search capabilities.

+

Transcript integrity

+
    +
  • Opt-in content signing. Per-channel or per-message choice to sign content, making it non-repudiable. This will be released in SimpleX Chat v7.
  • +
  • Subscriber transcript acknowledgment. Subscribers periodically sign a digest of received history ("I've seen it" rather than "I've authored it"), enabling detection of relay manipulation through diverging digests.
  • +
  • Merkle tree signing. Owner periodically publishes a signed Merkle root. Subscribers verify their copies against the owner's authoritative record.
  • +
+

End-to-end encrypted side conversations

+
    +
  • E2E encrypted support scope between subscriber and moderator/owner.
  • +
  • E2E encrypted DMs between members where channel settings permit, using standard SimpleX connection establishment.
  • +
  • Private channels where the entire content stream is encrypted to authorized subscribers. The relay becomes a conduit that sees neither content nor identity.
  • +
+

Relay addition and removal

+

Dynamic relay addition with cache population from existing relays or owner. Relay removal with subscriber migration. Relay rotation with continuity - new relay connects before old relay is removed. It will be added in v6.5.x.

+

Governance evolution

+
    +
  • Multiple owners (v7): concurrent administrative authority, any owner acts independently.
  • +
  • Multisig: M-of-N approval for administrative actions, with per-action quorums.
  • +
  • Programmable governance: rules defined as code in the channel definition.
  • +
+

Pre-moderation

+

Subscriber messages reviewed by moderators before becoming visible to all subscribers.

+

Scheduled delivery

+

Messages scheduled for future delivery, cached by relay until the scheduled time.

+ +

The relay loads link previews on behalf of the sender - it already sees message content, so it learns nothing new, and unlike the sender its IP is not linked to any identity.

+

Conclusion

+

SimpleX Channels enable a publisher to reach an unlimited audience without any infrastructure operator knowing who that audience is. No third party can seize the channel because owners hold the keys and the authoritative state on their own devices - relays only cache and forward. Owner signatures protect content integrity and the trust chain extends to all administrative roles. These properties require a network without participant identifiers - they cannot be added to a system that has them.

+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/docs/protocol/channels-protocol.html b/docs/protocol/channels-protocol.html new file mode 100644 index 0000000000..f900f7c593 --- /dev/null +++ b/docs/protocol/channels-protocol.html @@ -0,0 +1,1201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + +
+
+
+ +
+ + + + +

Revision 1, 2026-04-28

+

SimpleX Channels Protocol

+

For architecture, design rationale, security properties, and threat model, see SimpleX Channels Overview.

+

Table of contents

+ +

Protocol

+

This document describes the channel protocol as currently implemented. It builds on the SimpleX Chat Protocol, using the same message format and connection model, with extensions for relay-mediated distribution and cryptographic message signing.

+

Channel creation

+

Creating a channel involves generating cryptographic material, creating the channel link, and connecting relay members:

+
    +
  1. +

    Key generation. The owner generates an Ed25519 root key pair. The entity ID is computed as sha256(rootPubKey). A separate member key pair is generated for message signing, and an OwnerAuth entry is created, signed by the root key.

    +
  2. +
  3. +

    Link creation. The owner calls the agent's prepareConnectionLink API with the root key pair and entity ID. This returns a prepared link (including a ConnShortLink address) without any network calls. The link address is deterministic, derived from the fixed data hash, so it can be embedded in the group profile immediately.

    +
  4. +
  5. +

    Link data upload. The owner calls createConnectionForLink, which makes a single network call to create the SMP queue and upload the encrypted link data. The link's fixed data contains the root public key and connection request. The mutable user data contains the OwnerAuth array, the channel profile (including the entity ID and the link itself), and the initial subscriber count.

    +
  6. +
  7. +

    Relay invitation. For each selected relay, the owner sends a contact request containing an x.grp.relay.inv message with the channel's short link. The relay retrieves the link data, validates the channel profile, creates its own relay link (with the channel's entity ID in its immutable data), and responds with x.grp.relay.acpt containing its relay link.

    +
  8. +
  9. +

    Link update. As each relay accepts and provides its relay link, the owner validates that the relay link contains the correct entity ID, then adds the relay link to the channel link's mutable data.

    +
  10. +
  11. +

    Local record. The channel is stored on the owner's device with the root private key, member private key, and channel profile. This local record is the authoritative state of the channel.

    +
  12. +
+

Relay acceptance

+

When a relay receives an invitation to serve a channel, it validates the channel and creates its own relay link. This flow is currently part of channel creation; adding relays to an existing channel is planned but not yet implemented.

+
    +
  1. +

    Owner sends x.grp.relay.inv to the relay's contact address. This message includes the relay's member ID and role, the owner's profile, and the channel's short link.

    +
  2. +
  3. +

    Relay receives the invitation and creates a relay request record. A relay request worker processes it asynchronously.

    +
  4. +
  5. +

    The worker retrieves the channel's link data from the SMP server, extracts and validates the channel profile and owner authorization.

    +
  6. +
  7. +

    The relay creates its own contact address link (the relay link) with the channel's entity ID in the immutable fixed data.

    +
  8. +
  9. +

    The relay accepts the owner's connection request, sending its relay link in the acceptance.

    +
  10. +
  11. +

    The owner retrieves the relay link data, validates that the entity ID in the relay link matches the channel's entity ID, and adds the relay link to the channel link's user data.

    +
  12. +
+

TODO: Periodic monitoring where the relay retrieves channel link data to verify its relay link is still listed is planned but not yet implemented.

+

Subscriber connection

+

A subscriber joins a channel through the following flow:

+
    +
  1. +

    Link retrieval. The subscriber scans or receives the channel's short link. The client retrieves the link data, which contains the channel profile, owner authorization chain, and list of relay links.

    +
  2. +
  3. +

    Relay link resolution. For each relay link listed, the client resolves the ConnectionRequestUri from the relay's short link.

    +
  4. +
  5. +

    Connection. The client connects to relays - the first synchronously, the rest asynchronously. Each connection sends an x.member message with the subscriber's profile (or an incognito profile, created once and shared with all relays), member ID, and member signing key.

    +
  6. +
  7. +

    Relay acceptance. Each relay accepts the connection, creates a member record for the subscriber with the configured subscriber role (default observer), and sends an x.grp.link.inv message with the channel profile and group link invitation data.

    +
  8. +
  9. +

    Introduction. The relay introduces the new subscriber to the channel's moderators and owners by sending an x.grp.mem.new message. It also sends moderator/owner profiles to the subscriber.

    +
  10. +
  11. +

    History. If the channel has history sharing enabled, the relay sends recent cached history to the new subscriber.

    +
  12. +
+

The subscriber is functional (can receive messages) as soon as at least one relay connection succeeds. Additional relay connections provide redundancy and cross-relay consistency checking.

+

Message signing

+

Messages that alter the channel's roster, profile, or administrative state are cryptographically signed by the sending owner. Content messages are not signed by default; see Signing scope for the rationale.

+

Which messages require signatures:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MessageDescriptionSigned
x.grp.delDelete channelRequired
x.grp.infoUpdate channel profileRequired
x.grp.prefsUpdate channel preferencesRequired
x.grp.mem.delRemove memberRequired
x.grp.mem.roleChange member roleRequired
x.grp.mem.restrictRestrict memberRequired
x.grp.leaveLeave channelRequired (unverified allowed between subscribers)
x.infoUpdate member profileRequired (unverified allowed between subscribers)
x.msg.newContent messageNot signed
x.msg.updateEdit messageNot signed
x.msg.delDelete messageNot signed
+

Signing process:

+

The signing context binds the signature to a specific channel and sender:

+
bindingPrefix = smpEncode(CBGroup) <> smpEncode(publicGroupId, memberId)
+signedBytes   = bindingPrefix <> messageBody
+signature     = Ed25519.sign(memberPrivKey, signedBytes)
+
+

The binding prefix includes the chat binding tag ("G" for group), the channel's entity ID, and the sender's member ID. This prevents cross-channel and cross-member replay attacks - a signature valid in one channel cannot be reused in another.

+

Verification process:

+

When a subscriber receives a signed message:

+
    +
  1. +

    The signature is present: reconstruct the binding prefix from the channel's stored entity ID and the sender's member ID. Verify all signatures against the sender's stored public key. If all verify, the message is accepted as verified.

    +
  2. +
  3. +

    The signature is present but the sender's key is unknown: the message is accepted as signed-but-unverified only if the event does not require a signature. For x.grp.leave and x.info between subscribers whose keys haven't been exchanged yet, unverified signatures are permitted as a temporary measure.

    +
  4. +
  5. +

    No signature is present: the message is accepted only if the event does not require a signature (i.e., the channel does not use relays, or the event is a content message).

    +
  6. +
+

If verification fails for a message that requires a signature, the message is rejected and a bad signature event is shown to the user.

+

Message forwarding

+

Content originates on the owner's device and flows through relays to subscribers. The forwarding mechanism preserves the original message bytes, including any signature, without re-encoding:

+

Owner to Relay: The owner sends messages directly to each relay over their SMP connection. Messages are encoded in binary batch format.

+

Relay processing: When a relay receives a message from an owner, it:

+
    +
  1. Parses and processes the message locally (updating its cached state, e.g. for roster changes).
  2. +
  3. If the relay is configured to forward for this channel, creates a delivery task for each message that should be forwarded to subscribers. The task records the message ID, the sender's member ID, the broker timestamp, and whether the message was sent as the channel (not attributed to a specific owner).
  4. +
  5. The delivery task is persisted to the database for delivery reliability - ensuring forwarding can resume after a relay crash.
  6. +
+

Relay to Subscribers: A delivery task worker reads pending tasks, batches them into delivery jobs, and a delivery job worker sends each job to subscribers in paginated batches (using a cursor over group member IDs).

+

For forwarded messages from subscribers to owners (e.g. support scope messages), the relay wraps the message in a forwarding envelope:

+
forwardEnvelope = ">" <> smpEncode(GrpMsgForward) <> encodeBatchElement(signedMsg, msgBody)
+
+

This preserves the original message's signature bytes verbatim.

+

Binary batch format

+

Channels use a binary batch format that preserves exact message bytes for signature verification. This is distinct from the JSON array batching used by regular groups.

+
binaryBatch    = %s"=" elementCount *batchElement
+elementCount   = 1*1 OCTET                    ; 1-255 elements
+batchElement   = elementLen elementBody
+elementLen     = 2*2 OCTET                    ; 16-bit big-endian length
+
+elementBody    = signedElement / forwardElement / plainElement / fileElement
+
+signedElement  = %s"/" chatBinding sigCount *msgSignature jsonBody
+forwardElement = %s">" grpMsgForward (signedElement / plainElement)
+plainElement   = %s"{" *OCTET                 ; JSON message body
+fileElement    = %s"F" *OCTET                 ; binary file chunk
+
+chatBinding    = 1*1 OCTET                    ; "G" (group), "D" (direct), "C" (channel)
+sigCount       = 1*1 OCTET                    ; number of signatures (1-255)
+msgSignature   = keyRef sigBytes
+keyRef         = %s"M"                        ; member key reference
+sigBytes       = 64*64 OCTET                  ; Ed25519 signature
+
+grpMsgForward  = fwdSender brokerTs
+fwdSender      = memberFwd / channelFwd
+memberFwd      = %s"M" memberId memberName    ; attributed to specific member
+channelFwd     = %s"C"                        ; attributed to channel as sender
+brokerTs       = 8*8 OCTET                    ; UTC system time
+
+

The parser (parseChatMessages) dispatches on the first byte:

+
    +
  • '=' -> binary batch (new format, used by channels)
  • +
  • 'X' -> compressed (decompress, then re-parse)
  • +
  • '[' -> JSON array (legacy group format)
  • +
  • '{' -> single JSON message
  • +
+

Forward elements contain the original message bytes verbatim. The relay does not re-encode the inner message. This is what makes signature verification possible after forwarding: the exact bytes that were signed by the owner are preserved through the relay.

+

Nested forwarding (> inside >) is explicitly rejected by the parser.

+

Delivery pipeline

+

The relay's delivery pipeline has two stages, both backed by persistent database tables for delivery reliability (not for authoritative storage - the relay's database is a delivery queue, not a content database):

+

Stage 1: Delivery tasks. When the relay receives a message from an owner that should be forwarded, it creates a delivery_task record:

+
delivery_task:
+  group_id, worker_scope, job_scope,
+  sender_group_member_id, message_id,
+  message_from_channel (bool),
+  task_status (new -> processed)
+
+

A task worker (one per group per scope) reads pending tasks, batches multiple tasks into a single binary batch body, and creates a delivery job.

+

Stage 2: Delivery jobs. A delivery job contains the pre-encoded batch body and a cursor for paginated delivery:

+
delivery_job:
+  group_id, worker_scope, job_scope,
+  body (pre-encoded binary batch),
+  cursor_group_member_id,
+  job_status (pending -> complete)
+
+

A job worker reads the body and delivers it to subscribers in paginated batches. For each page, it loads a bucket of subscribers by cursor position, sends the body to all of them, advances the cursor, and continues until all subscribers have been served. This avoids loading all subscribers into memory at once.

+

For subsequent subscribers in a batch, the agent uses a value reference to the first subscriber's message body, avoiding redundant data transmission to the SMP server.

+

Message deduplication

+

When multiple relays serve the same channel, each subscriber receives the same message from each relay independently. Deduplication is performed at the subscriber's client level using the message's shared message ID:

+
    +
  • When saving a received message, the client checks whether a message with the same shared ID already exists for this group.
  • +
  • If a duplicate is found, the message is silently dropped (in channels with relays).
  • +
  • In non-relay groups, duplicate detection triggers a x.grp.mem.con notification to the forwarding member.
  • +
+

This is essentially cache coherence verification - comparing what was received from one cache node against another. TODO: Currently, deduplication only detects the presence of duplicates. The protocol design includes provisions for detecting differences between relay-delivered copies of the same message (hash comparison, UI indicators for discrepancies). This is described in the channels forwarding RFC and is not yet implemented.

+

Channel-as-sender messages

+

Owners can send messages attributed to the channel rather than to themselves. When asGroup = True is set in the message container, the relay forwards the message with a channel-as-sender tag instead of attributing it to a specific member. On the subscriber side, such messages are displayed as coming from the channel (using the channel's profile image and name) rather than from a specific owner.

+

This will be useful for channels with multiple owners (not yet implemented at application level) where the identity of the specific sender should not be visible to subscribers. The relay must respect this directive; ignoring it and revealing the sending owner's identity is a threat vector (detectable out-of-band by members communicating with the owner).

+

The forwarding binding prefix for channel-as-sender messages uses CBChannel instead of CBGroup, and includes only the channel's entity ID (not the sender's member ID):

+
channelBinding = smpEncode(CBChannel) <> smpEncode(publicGroupId)
+
+

Member support scope

+

Channels support a member support scope - a private side-channel between a subscriber and the channel's moderators/owners. Messages sent in the support scope are delivered only to moderators and the scoped subscriber, not to all subscribers.

+

A support-scoped message includes the target member's ID. The delivery pipeline uses a separate job scope for support messages, loading only the scoped member and moderators rather than all subscribers.

+

Support scope messages are visible only to the subscriber who initiated the support conversation and to the channel's moderators. Other subscribers cannot see them. This allows subscribers to report issues, appeal moderation decisions, or communicate with administrators without revealing their identity to other subscribers.

+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/docs/protocol/simplex-chat.html b/docs/protocol/simplex-chat.html index 78df4014dd..1ed02b0730 100644 --- a/docs/protocol/simplex-chat.html +++ b/docs/protocol/simplex-chat.html @@ -954,6 +954,9 @@ eventWord = 1* ALPHA

x.grp.info message is sent to all members by the member who updated group profile. Only group owners can update group profiles. Clients MAY implement some conflict resolution strategy - it is currently not implemented by SimpleX Chat client. This message MUST only be sent by members with owner role. Receiving clients MUST ignore this message if it is received from member other than with owner role.

x.grp.direct.inv message is sent to a group member to propose establishing a direct connection between members, thus creating a contact with another member.

x.grp.msg.forward message is sent by inviting member to forward messages between introduced members, while they are connecting.

+

Channels: relay-mediated groups

+

Channels are groups where message delivery is mediated by dedicated relay members rather than by direct connections between all members. Channels extend the group sub-protocol with additional roles (relay, observer), message signing for administrative actions, a binary batch format for signed and forwarded messages, and an asynchronous delivery pipeline.

+

For architecture and design rationale, see SimpleX Channels Overview. For protocol-level detail - wire formats, message types, signing mechanics, delivery pipeline - see SimpleX Channels Protocol.

Sub-protocol for WebRTC audio/video calls

This sub-protocol is used to send call invitations and to negotiate end-to-end encryption keys and pass WebRTC signalling information.

These message are used for WebRTC calls:

@@ -972,12 +975,13 @@ eventWord = 1* ALPHA

Threat model

-

This threat model compliments SMP, XFTP, push notifications and XRCP protocols threat models:

+

This threat model complements SMP, XFTP, push notifications and XRCP protocols threat models, as well as the channel-specific threat model:

A user's contact

can:

@@ -1052,6 +1056,38 @@ eventWord = 1* ALPHA +

A channel relay

+

For the full channel threat model, see SimpleX Channels: threat model.

+

can:

+ +

cannot:

+