Private group membership on Stellar using zero-knowledge proofs.
Website: onym.chat
A naive on-chain group registry leaks the social graph twice over: the member list is public, and every update is signed by a recognizable Stellar account. Stellar MLS replaces the member list with an opaque commitment and replaces the update signature with a Groth16 proof submitted through a fee-decoupling relayer. The blockchain stores 32 bytes per group and verifies membership in 4 BLS12-381 host calls — constant cost whether the group has 2 members or 2,048.
┌──────────────────┐ ┌──────────────────┐
│ iOS / macOS app │ │ Android app │
│ (SwiftUI ref.) │ │ (Compose ref.) │
└────────┬─────────┘ └────────┬─────────┘
│ │
┌────────▼─────────┐ ┌────────▼─────────┐
│ swift-mls SDK │ │ kotlin-mls SDK │
│ (XCFramework) │ │ (JNI .so) │
└────────┬─────────┘ └────────┬─────────┘
│ │
└─────────────┬─────────────┘
│ Rust core (src/)
│ Groth16 prover · Poseidon
│ Merkle tree · BLS12-381
▼
┌──────────┐ ┌────────────────────┐
│ Relayer │──proof──▶│ Soroban contract │
│ (Axum) │ │ (SEP-XXXX, BLS) │
└──────────┘ └────────────────────┘
Stellar network
ciphertext side-channel (not trusted for integrity):
Nostr relay (strfry) + Blossom blob store
The relayer pays fees so the transaction signer cannot be linked to a group member. The contract verifies a Groth16 proof that the submitter knows a secret whose Poseidon hash sits in the group's committed Merkle tree, bound to the current epoch and salt. Nostr and Blossom carry end-to-end encrypted messages and blobs out of band — the contract never sees plaintext.
- iOS / macOS — see
swift-mls/README.mdfor XCFramework install,SEPContractClient, andSEPInvitationSender. - Android — see
kotlin-mls/README.mdfor JNI bridge setup,SEPProofGenerator, andRustBackedNostrSigner.
Fully-worked integrations using both SDKs:
clients/ios/— SwiftUI chat clientclients/android/— Jetpack Compose chat client
One command provisions a Digital Ocean droplet, configures Cloudflare DNS, obtains Let's Encrypt certificates, and starts the relayer, Nostr relay (strfry), Blossom, and nginx:
./deploy/digitalocean/deploy.shIdempotent; saves state to .env. See docs/mainnet-deployment.md for contract deployment.
git clone https://github.com/rinat-enikeev/stellar-mls.git
cd stellar-mls
cargo test # Rust core + tests
./scripts/build-xcframework.sh # iOS XCFramework
./scripts/build-android.sh # Android JNI libs
stellar contract build --manifest-path contracts/sep-xxxx/Cargo.tomlConfigure relayer/.env (contract ID, RPC) and optionally .env (DOMAIN=onym.chat) to auto-wire the apps to your infrastructure.
| Path | Language | Role |
|---|---|---|
src/ |
Rust | ZK circuits, Poseidon Merkle trees, Groth16 prover, C FFI + JNI bridge |
contracts/sep-xxxx/ |
Rust (Soroban) | On-chain group state, BLS12-381 proof verification |
swift-mls/ |
Swift | iOS/macOS SDK |
kotlin-mls/ |
Kotlin | Android SDK |
clients/ |
SwiftUI / Compose | Reference chat apps |
relayer/ |
Rust (Axum) | Fee-decoupling HTTP relayer |
deploy/ |
Docker / Nginx | Self-hosted stack |
docs/ |
Markdown | Specification, audits, design docs, ceremony runbooks |
The contract ABI, group tier parameters (Small/Medium/Large — 32 / 256 / 2,048 members), and cryptographic construction details live in the SEP-XXXX specification.
- Membership privacy: the contract never learns who is in any group
- Proof binding: every group operation requires a valid ZK proof
- Epoch monotonicity: no replays, no forks
- Constant verification cost: same 4 host function calls regardless of group size
- End-to-end encryption: all Nostr traffic is AES-256-GCM; relays see ciphertext only
- Fee-payer anonymity without a relayer
- Traffic analysis resistance on Nostr
- Automatic recovery from BLS key compromise (requires re-keying)
The system's privacy claims rest on Groth16 circuit soundness, the Soroban verifier's correct use of BLS12-381 host calls, and key handling inside the SDKs. Start here:
docs/sep.md— SEP-XXXX specification: commitment scheme, Groth16 relations, Soroban interfaceSECURITY.md— threat model, in/out scope, private disclosure channelsdocs/audit-report.md— current audit (2026-04, 6 workstreams)docs/protocol-soundness-analysis.md— smart-contract layer: commitment canonicalization, epoch monotonicity, replay preventiondocs/proof-of-soundness.mdanddocs/proof-of-correctness.md— circuit-level proofs- Postmortems — real incidents: co-membership leak, secure member removal, unbound new commitment
paper/venue/ieee/onym-ieee.pdf— IEEE experience report (alpha testnet; load-bearing caveats on trusted-setup participants and small-group unlinkability)
Please disclose vulnerabilities privately via the channels in SECURITY.md; do not open public issues for security reports.
Full specification, design docs, ceremony runbooks, deployment guides, and audit reports live in docs/.
MIT. See LICENSE.