NAOMS Devlog

Building a sovereign, local-first memory & identity system β€” in the open, honestly.

One Locked Room for the Whole Call, Not One Per Pair

How an encrypted group call is built: a single shared encryption group with exactly one host who opens it and lets everyone in

Technology Architect April 21, 2026Β·7 min readΒ·messaging
TL;DR When several people join one encrypted call, there is exactly one locked room for the whole call, and exactly one host who opens it and lets everyone in. Here is why that has to be the shape β€” grounded in the invitation fan-out that shipped 2026-04-21 and the single-owner rule that followed.

Here's a question that sounds trivial until you try to build it: when three people are on an end-to-end encrypted call, how many encryption groups are there?

The answer NAOMS is built on is one β€” one shared encryption group for the whole call, with a single owner. This is a concept piece about why that has to be exactly the shape, and why the alternatives that look fine are not.

How an encrypted group call is supposed to work

Take the words apart first. End-to-end encrypted means the audio is scrambled on the sender's device and only unscrambled on the recipients' devices β€” nothing in between, including any server the packets pass through, can hear it. To unscramble it, the participants must share a secret. So the real design question in a group call is not "which cipher?" β€” it is who holds the shared secret, and how does it change as people come and go?

That is the job of MLS, Messaging Layer Security: an open standard for end-to-end encryption among many participants rather than two. Its core idea is a group β€” a shared cryptographic state that every member holds a copy of, carrying the current key and the current membership list together. When someone joins or leaves, the group's state advances and everyone's copy advances with it, so the key material and the member list can never drift apart. Joining is not a negotiation between the newcomer and each existing member; it is a single message called a welcome, produced by a member of the group and processed by the newcomer, after which the newcomer simply is in the group and holds the same shared state as everyone else.

NAOMS uses one such group per call, named for the call itself. Every participant is a member of that one group. Audio is encrypted once, under the group's shared secret, for everyone in it.

Layered on top is the rule that makes it converge: only the call's creator creates the group, and only the creator sends out the welcomes. Everyone else joins. The person who started the call runs one MLS handshake per person who arrives β€” but always against the same group, never a fresh one β€” and each joiner processes their own welcome to enter it. That is the fan-out that shipped on 2026-04-21, and the description of it is worth quoting because it is the whole idea in one line: Alice runs one 2-party dance per joiner against a single per-call group; joiners each process their own welcome.

Read that twice. There is one group. There are N handshakes, one per arrival, all pointed at it. The result is a single shared encryption state that everyone is a member of, built up one handshake at a time, with one being driving the whole thing. Membership has a single source of truth because group creation has a single owner.

Two properties follow, and they are the reason the shape is chosen:

Cost grows with people, not with pairs. Each participant maintains one group membership, not one relationship per other participant. Each audio frame is encrypted once, not once per recipient.

"Who is in this call" is a fact, not an inference. It is written in the group state that every member holds. There is a clean answer to did everyone leave? and to is this person authorized to be here?, and a join or a leave is one atomic change to one object rather than a flurry of independent updates that could disagree.

The design published the same day names what this unlocks β€” per-channel signing shares, the channel ceremony driver, per-peer connection bookkeeping β€” and notes that each can now ship independently. That is the signature of getting a core decision right: the hard part, once owned, decomposes the rest of the work instead of entangling it.

Proving it converges rather than asserting it

A design that "should compose" and a design that is proven to compose are different things, and the Honesty axiom β€” the project's standing commitment not to claim more than it has verified β€” does not let us ship the first one wearing the second one's clothes. So the fan-out work did not merely assert that the two-person handshake generalizes to a group. It codified the convergence as a test: a harness that snapshots and restores each participant's state so three independent MLS endpoints can be stood up at once, the creator's one-handshake-per-joiner fan-out is run, and all three are then asserted to have arrived at the same group state.

The regression guard beside it is the subtle part. The original two-person handshake test stayed green, because the N-party fan-out had to be the same handshake the two-person path already used β€” not a parallel implementation that could drift away from it. One mechanism, proven to scale; not two mechanisms that agree today.

This is also why switching the native MLS engine on by default earlier the same day is load-bearing underneath all of it. The convergence had to be proven on the real protocol implementation β€” the one production uses β€” and not against a simulated stand-in that might converge for reasons the real protocol wouldn't. A convergence proof against a fake is a proof about the fake.

What was wrong

Two things, one of them a design most people reach for first, the other a race hiding inside the correct design.

The per-pair design. The intuitive answer to "how many encryption groups?" is one per pair: Alice↔Bob, Bob↔Carol, Alice↔Carol, three separately encrypted links like three phone lines. Every link is genuinely end-to-end encrypted, so it feels safe. It rots three ways, and worse as the call grows. It is N-squared β€” three people is three links, five is ten, ten is forty-five, with a separate session to maintain and a separate encryption of every audio frame for every recipient. There is no shared notion of "the call" β€” membership is not a fact anyone holds, only an emergent property of which pairs happen to have channels open, so the single most important fact in the system is scattered. And membership changes become a renegotiation storm β€” a fourth person joining means three new handshakes, a departure means tearing links down one at a time and hoping nobody missed the memo, with no atomic "the group changed" event.

The founder race. Choosing one group per call does not by itself close the hole. If the answer to who creates the group? is "whoever gets there first," the race comes straight back: three participants each trying to found the per-call group produces three candidate groups for one call β€” conflicting groups, exactly the thing the single-group design existed to prevent, now hiding inside it. That is the failure this article is named for, and it is the one that had to be closed explicitly.

The deeper problem under both is the one this project keeps running into: multiple parties each own a piece of shared state, and now they can disagree. Same failure mode as two writers racing on a shared log, or three machines each believing they are the membership authority. Per-pair encryption is not wrong because the crypto is weak. It is wrong because it has no owner.

How it was fixed

The single-owner rule was made explicit and enforced in the mesh milestone that landed 2026-04-26: only the creator creates the group, and only the creator fans out the call offer. One being owns the group's existence, one being owns the invitation fan-out, and it is the same being β€” the person who started the call. The observable payoff was mesh audio between every pair coming out symmetric, with the integration suite fully green: the last place two parties could disagree about whose group is real, removed.

To be exact about dates, since both halves are real and they are not the same day: the convergence proof is the 21st's; the single-owner enforcement is the 26th's. Together they are the answer to the title.

Why it's built this way

The whole arc β€” from "one group per call" to "one owner per group" β€” is the same principle the rest of NAOMS is built on, applied to encrypted audio: pick one honest owner for a piece of shared state instead of hoping concurrent writers agree.

One MLS group per call gives you a single shared secret, a single membership fact, and atomic group changes. The single-owner-creates rule removes the last hidden race β€” who founds the group. The crypto is strong in both designs; the difference is entirely about ownership of state. That is not a calling insight, it's the project's whole thesis, showing up in the place where getting it wrong would have leaked the most intimate data we carry. One call, one group, one owner. Everyone else is welcome β€” literally, via an MLS welcome message β€” to join.

Related: Browser-to-Browser Calls, No Server in the Middle Β· Week 6.


Written by AI agents from real project logs; owned and edited by Mujo.

← more in Technology   home ✦   all β†’