DEV Community

Mohammad Taha Azizi Ahad
Mohammad Taha Azizi Ahad

Posted on

When someone leaves the group: how my messenger rotates group keys

One-to-one chats are the easy case. Group chats are where key management gets genuinely hard, because the group itself changes. Someone joins. Someone leaves. Someone's phone is replaced. Every one of those events has to change what the group can read — without breaking the messages already in flight.

This post is about how my protocol, PQ-MPRBA, handles that: a small state machine called the Group Epoch FSM.

The two promises a group chat has to keep

When a member leaves, they must not be able to read future messages. That is forward secrecy for groups.

When a member joins, they must not be able to read past messages. That is backward secrecy for groups.

Both sound obvious. Both are easy to get wrong. The classic failure is rotating the key but letting old messages stay decryptable with the old key, or rotating so aggressively that half the group loses messages during the transition.

Epochs instead of one key

Instead of one group key, the group moves through epochs. Each epoch has its own key material, and the group is always in one of three states:

  • STABLE — normal chatting, one current epoch.
  • ROTATING — a membership change has triggered a rotation, and the new epoch is being distributed.
  • STABLE again — everyone has the new epoch, and the old one is retired.

The state machine is deliberately boring. There are no clever shortcuts, just three states and clear transitions. In security code, boring is a feature.

The grace buffer that saves your messages

The tricky part is the transition. When rotation starts, some messages encrypted under the old epoch are still traveling through the network. If you delete the old key the instant rotation begins, those messages arrive undecryptable and the chat looks broken.

So the protocol keeps a grace buffer of three epochs. During rotation, the group can still decrypt messages from the previous epochs while everyone moves to the new one. Once the transition is complete and the buffer slides forward, the old keys are wiped — with the same zeroization discipline as the one-to-one ratchet.

Three epochs is a judgment call, not a law of nature. One would break messages. Ten would keep old keys alive too long. Three covers a realistic transition window without turning the buffer into an archive.

Why this matters beyond groups

The same pattern shows up everywhere keys have a lifetime: sessions, devices, teams. The lesson is general — a key rotation is not an event, it is a transition, and transitions need a defined state machine, a bounded grace period, and a real deletion at the end. Skip any of the three and you get either broken messages or keys that never die.

What is still honest to say

As with the rest of PQ-MPRBA, this is experimental work by one person, not independently audited. The group rotation is implemented and used in my messenger, but I will not claim it has survived adversarial review. The design is public so it can be criticized — that is the point of publishing it.

The code is open source: https://github.com/indirect-b/chat-app

If you have built group key rotation yourself, I would love to hear how you sized your grace window — that is the number I am least sure about.

Top comments (0)