Guide 4 of 9

Groups

The N-sender-keys model, off-chain membership, and what rotation does and does not guarantee.

4

Groups

A DChat group has no shared secret. Every member holds their own symmetric sending key, and the group's confidentiality is built entirely out of the pairwise channel described above.

Each member's sender key is 32 bytes drawn from the platform CSPRNG - not derived from the identity key, so it discloses nothing about the account that owns it. Distribution is individual: a member's sender key is wrapped separately for every other member over that member's own pairwise ECDH channel, so no server, relay or third party ever sees a sender key in the clear. A message to the group is encrypted once, under the sender's own key, and recipients pick the right decryption key by the sender DID and key generation carried in the envelope.

The app enforces a hard cap of 100 members shown at creation and checked again in the member picker. There are exactly two roles - Member and Admin - with no separate Owner in the data model; whoever creates a group is an Admin from the start, with no permissions beyond what any other Admin has. Invite links can add someone directly or route them through an admin-approved join request, depending on configuration, and an admin decides who gets in when approval is required. A new member never sees history from before they joined - not as a policy choice, but because they were never issued the sender keys that protected those earlier messages; there is nothing for their device to decrypt going backward even if it wanted to.

There is no separate "channel" type layered on top of this. A DChat group is the only multi-person conversation primitive, capped at 100 members under the Member/Admin model above - there is no broadcast-style, unlimited-subscriber channel, and group identifiers share the same dc bech32 prefix as account addresses, validated against it before any key operation touches the group.

Group state itself is not on the chain and is not held by any server: membership, admin status, name and photo changes travel as unicast control messages fanned out to each member individually, ordered by a client-side StateVersion. Whether a change has reached consensus among admins is asserted client-side too. This makes groups fully client-governed, and it comes with a real limitation worth naming plainly: post-removal key rotation is a client responsibility, not something the SDK enforces. The SDK exposes a rotation call; the DChat app invokes it when someone is removed or leaves. A third-party client built on the SDK that skips this call leaves a departed member able to decrypt group traffic until the routine periodic rotation eventually catches up. Rotation also iterates members one at a time and tolerates a failure on any single member without stopping, so a partial rotation - some members updated, others not yet - is a real possible state, not a hypothetical edge case.

One recovery mechanism exists for the fully-offline case: an Ed25519-signed IPNS "group authority" pointer lets someone added to a group while every other member is offline fetch the latest admin-signed membership snapshot without needing a live peer at all.

Related: Spec §4 - group messages · FAQ - what happens to keys when someone leaves a group?