A Group That Knows You're Real Without Learning Your Name
Joining a group in NAOMS no longer puts your permanent identity in front of everyone else in it. You are pseudonymous by default, and what you show each group is a card you compose yourself β a display name of your choosing, or nothing but verified merit and reputation, published under a per-group persona rather than your root identity. You decide what to divulge, one group at a time.
Think about what happens the moment you join a group chat somewhere else. Before you have said a word, the room has already learned things about you: the name on your account, probably the photo, often the phone number that got you in. Membership and identity arrive together, welded, and there is no dial between them.
We have chipped at this before. Earlier this summer we stopped stamping every contribution you make to a group with your permanent identity β what you share with the group doesn't carry your name. That fixed what your contributions said about you. This is the other half: what your membership says about you.
We wanted the dial. A group ought to be able to know something true and useful β a real member is here, allowed to be here β without that same act handing everyone your identity.
The felt version
You accept an invitation. You appear in the group.
What the other members see is a member β present, connected, part of the picture β with no name attached. Not a blank, not an error: a deliberate node that stands for someone real who belongs here. If one of them already knows you personally, their own device may quietly label you with the name they already had for you. It does that on their machine, from their own address book, and it tells nobody. To everyone else in the room, you are still nameless.
Alongside that nameless node, you compose a card for this group β and this is where the choosing happens. You pick a display name, and it does not have to be the name on your passport or the one you use anywhere else. You pick a colour and, if you like, a photo. You toggle on whichever verified facts about yourself you want this particular group to see, and leave the rest off.
You can also turn none of them on. A card can carry nothing but your standing β what you have done, what others have vouched for β with no name and no contact details attached to it at all. That is a real option, not a degraded one: merit and reputation, unhooked from who you are.
Whatever you choose, it goes out under a persona belonging to this group. Give your book club a name; the neighbourhood group still sees only what you gave it. There is no global "profile" doing this behind your back, and no step at which your permanent identity is the thing being published.
What your device actually publishes
Here is the mechanism worth understanding, and it is smaller than you would expect.
When you join a group on your own device, your device takes your permanent identifier, mixes it with the identity of that specific group, and runs the pair through a one-way function. Out comes a fingerprint. That is what goes into the group β not your identifier, which never leaves your machine.
flowchart TD A["You accept an invitation
on your own device"] --> B["your permanent identifier
+ this group's identity"] B --> C["one-way function"] C --> D["fingerprint"] D --> E["published to the group:
a member node holding
ONLY the fingerprint"] B -.->|"never leaves your device"| X["your identifier, name,
email, phone"] A2["The same you,
joining a different group"] --> B2["same identifier
+ a DIFFERENT group"] --> C2["one-way function"] --> D2["a COMPLETELY
different fingerprint"]
Two properties fall out of that construction, and they pull in opposite directions on purpose.
Within one group, the fingerprint is stable. It is computed the same way by anyone who has the same two inputs. That is what makes local naming possible: a member who already has you in their own address book can compute your fingerprint for this group on their own machine and discover that the nameless node over there is you. They already knew your name. Nothing new was disclosed to them β the group simply stopped being the thing that told them. We wrote about that side of it separately in your friends get their names back, on your screen only.
Across groups, it is not stable. Because the group's own identity is mixed in, the same person produces a completely different fingerprint in every group. Someone holding both groups' member lists cannot line them up against each other and rebuild a person's social graph out of the overlap.
The membership node that gets stored holds the fingerprint and its connections. No name, no email address, no phone number, and not the identifier it was derived from.
That node is your membership. Your card is the separate thing beside it, and it is the one you fill in.
The card is yours to compose
The card your group sees is built from what you toggled on, and it is published under a persona derived for that group β a distinct identifier computed for this card in this group. The link between that persona and your real identity is kept only in encrypted form on your own machine; the key material the system stores alongside a persona carries no reference back to your master identity at all.
So the ladder is not "nameless or exposed". It is:
- nothing but a fingerprint β you are present, and that is all anyone learns;
- standing without identity β verified facts about what you have done, attached to a persona rather than to you;
- a chosen name β one you picked for this group, which need not be one you use elsewhere;
- contactable β an email, an address, whatever you deliberately attach.
Every rung is a decision you make for one group. None of them is the default, because the default is the bottom rung.
One honest limit while we are here: the verified facts you attach to a card do not yet propagate to your co-members' devices the way the card's own properties do. The code says so in its own comment β cross-peer visibility of those fields is follow-on work, not something that quietly works today.
The limit that matters most
We are going to be precise about this, because the obvious reading of the paragraph above is stronger than what we built.
The fingerprint is not unlinkable to everybody. It is unlinkable to someone who does not already know you.
The group's identity is visible to its members, and the fingerprint is computed from your permanent identifier. So anyone who already holds your identifier β every one of your existing contacts β can compute what your fingerprint would be in any group whose identity they know, and check whether that fingerprint is present. That is not a flaw in the construction; it is the same property that makes local naming work, seen from an angle you may not like. It cannot be one without being the other.
So the honest statement is: a stranger learns nothing, and a group you leave keeps nothing that identifies you β but a contact of yours who wonders whether you are in a particular group can find out, if they know which group to ask about. Closing that gap needs a different construction, where the fingerprint comes from a secret only you hold and travels with a proof. That tier is designed and named as future work. It is not what shipped.
The ceiling on what a group can ask for
There was a second, quieter hole. A group could describe what it wanted new members to share, and joining would just⦠comply.
Now that request has a ceiling. A group may still recommend that members share names or cards, but the automatic share that happens when you join is clamped to the name-less level regardless of what was asked for. You can always choose to go further by hand, later. The automatic path cannot take you there.
The part of that we are proudest of is small and unglamorous: the consent receipt you get records what was actually shared after the clamp β never the group's original, larger request. A receipt that records the ask rather than the act is a lie in a helpful voice, and we have written before about why a system that lies to itself cannot be whole.
Revealing one true thing instead of the whole document
Pseudonymous-by-default only works if there is a graceful way to prove something specific when it matters β without producing the underlying document that also contains everything else about you.
We designed that a while ago and were candid at the time that the first version stood a simulation in for the real mathematics: prove you're over 18 without showing your birthday. That placeholder is now gone. The real mathematics landed with this work, from a published implementation of a standard construction. Validity now comes from the proof itself: alter a revealed value, forge a proof, present it with the wrong challenge, and verification fails as mathematics rather than as a length check.
That matters more than it sounds. A simulated proof that always says yes is indistinguishable from a real one right up until someone attacks it.
What we did not do
Four honest boundaries. Three were recorded in the project's own sign-off; the fourth we found by attacking our own first draft of this article, and it is the reason you are reading a second one.
Sharing a friend into a group was fixed by removing, not by replacing. The old leak was real: mentioning a friend who wasn't a member used to put their actual details in front of every co-member. That is closed β a share into a group now carries no friend list at all. What is not built is the graceful version, where those friends come back as name-less fingerprints so the group's map of who-knows-whom still joins up without carrying anyone's identity. Our first draft of this article described that graceful version as though it had shipped. It has not. The code says so in its own comments, and we would rather that kind of statement live there than in a blog post.
The fingerprint is not yet a zero-knowledge proof. It is a one-way hash, salted per group. It carries no personal details β but the limits section above is the real boundary, and the person who published it knows who it stands for.
If someone else approves your join, no fingerprint is published at all. The fingerprint is computed on your device from your identifier, so it exists only when you join yourself. A join completed on an approver's device produces a member with no fingerprint β nothing leaks, but local naming will not find you either.
Asking to join a closed group from the outside doesn't travel yet. The approval side and the preview of a closed group are in place. What isn't wired is the delivery of a stranger's request across to the person who could approve it. The sign-off also lists the invited-and-accepting path as landed-parts rather than working end to end, and we are repeating that here rather than rounding it up.
The reason to care
Most systems treat identity as the entry fee for belonging. You hand over who you are, and in exchange you get to be in the room. It feels like an exchange, but nothing about the room actually requires it β the room needs to know you're allowed in, which is a much smaller fact than your name.
Separating those two has consequences you feel later rather than immediately. A group you leave keeps no dossier on you. A group that is breached leaks fingerprints rather than a member list with phone numbers. And the person who does know you still sees your name, because their own device already knew it β which is the version of recognition that was always honest anyway.
The group knows a real member is there. It does not know who you are. Both of those, at once, is the point.
Written by AI agents from real project logs; owned and edited by Mujo.