the answer
No company in the loop.
Just math, on a public ledger.
Onym replaces the trusted operator with four moving parts: a key ratchet on your phone, a zero-knowledge proof of group membership, a swappable transport, and group rules pinned to a public smart contract. Together they hide message content and sender identity from the network. What they do not hide is named in the threat model.
the math, as it runs
Keys never leave your phone.
The chain only sees a proof.
A sender proves “a member sent this” without revealing which member. The group never learns who. The transport sees ciphertext and timing, not content and not which member sent it.
the pipe is replaceable
Relays are dumb pipes.
Swap them like cables.
Onym ships with Nostr today and is indifferent to whatever ships next. A relay sees opaque blobs going past — no sender, no recipient, no message. Use the default, run your own, or borrow a friend’s.
Every blob looks the same to every relay. Swap the relay; the contents stay opaque. The transport is a courier with a sealed envelope and no return address.
rules, in public
No operator console.
A contract anyone can read.
The rules are visible. The runtime is the rules. There is no admin who can override them, no console that can suspend you, no version of the app that does something different than what you can read.
the payoff (and the limits)
Hidden by construction.
Honest about what isn't.
What is not hidden — connection timing, group existence, group-size range, on-chain operation timing — is named in the threat model.
the four flows
What happens, in order,
when you press a button.
Identity creation
[device] [network] | | generate BIP-39 (128-bit) | derive secp256k1, Ed25519, | X25519, BLS12-381 keys | store on device only | | (no traffic. identity is local | until the first action.)
Group creation
[founder] [relayer] [Soroban contract] | pick group_id | compute commitment | sign Soroban auth | for create_group | |--- submit ---->| |-- Stellar tx+fee -->| | verify caller auth | verify ZK proof | check id unused | store commitment | emit GroupCreated |<-- tx confirmed ----| |<- confirmed ---|
Message send
[sender] [Nostr relay] [recipients] | encrypt to members | sign with sender key | |--- publish blob -->| |-- fan out -->| | decrypt, | verify sig, | render
Member action (admit · vote · update)
[member] [relayer] [Soroban contract] | compute new commitment | build ZK proof of | legal transition | NO user signature | |--- submit ----->| |-- Stellar tx+fee -->| | verify ZK proof | check c_old matches | store c_new |<-- tx confirmed ----| |<- confirmed ----|
Every flow involves three parties at most: your device, optionally a relayer to pay Stellar fees, and the Soroban contract on chain. The relayer never holds plaintext or signing authority. The contract is the only durable shared state.