noone.

Censorship-resistant, end-to-end encrypted voice, video, and messaging over Nostr.

100% open source. Zero server-side trust. Every line of code is auditable.

Architecture

BROWSER (STATIC SPA) RUST / WASM CRYPTO secp256k1 X25519 + ML-KEM-768 Ed25519 Double Ratchet NIP-59 seal JS CLIENT LAYER WebAuthn PRF IndexedDB vault Relay manager Trust store P2P + group crypto UI (HTML) Emoji pairing Chat + groups Voice / video calls Contacts Apps platform WebRTC wss:// Nostr Relay A Nostr Relay B Nostr Relay C Relays see encrypted blobs only. Zero metadata.

Key invariants

Codebase Structure

PathPurposeLines
crates/nostrcomm-crypto/src/lib.rsWASM entry -- 20+ exported functions~500
crates/nostrcomm-crypto/src/identity.rsKey derivation (PBKDF2+HKDF), device certificates~500
crates/nostrcomm-crypto/src/envelope.rsNIP-59 sealed sender (X25519 + ML-KEM-768 hybrid)~300
crates/nostrcomm-crypto/src/ratchet.rsSignal Double Ratchet~350
crates/nostrcomm-crypto/src/pairing.rsEmoji pairing codes (45-emoji alphabet)~200
web/src/main.jsApp shell, screen routing, inbox handler, group chat~2500
web/src/vault.jsIndexedDB encrypted storage (AES-GCM)~400
web/src/relay.jsMulti-relay Nostr pub/sub manager~170
web/src/call.jsWebRTC call manager (1:1 voice/video)~310
web/src/group-call.jsMesh P2P group voice calls~220
web/src/group-crypto.jsGroup E2E encryption (AES-GCM session keys)~95
web/src/p2p.jsWebRTC DataChannel for direct P2P messaging~420
web/src/radio.jsUltra-low-bandwidth voice (8-12 kbps Opus)~300
web/src/apps/sdk.jsApps SDK v2 (sandbox interface for apps)~160
web/src/apps/chess.jsChess game (full rules + spectator mode)~660
web/src/apps/sketch.jsReal-time collaborative whiteboard~390
web/src/apps/location.jsGPS sharing over OSM tiles~550

How Messages Work

1:1 Message Flow

Sender WASM SEAL ECDH + ML-KEM ChaCha20-Poly1305 plain Nostr Relay kind 1059 sealed WASM UNSEAL ECDH + ML-KEM Decrypt + verify Outer event uses fresh ephemeral keypair Real sender hidden from relay GROUP: random AES-256 session key encrypts plaintext once, then sealed individually per member (N events)

P2P DataChannel (when both online)

Alice Bob WebRTC DataChannel (hybrid encrypted) ~50ms latency, bypasses relays, signaling via sealed Nostr events (kind 25002)

Identity & Key Management

Key Derivation

PRF output (32B) PIN (4-12 chars) Salt (32B) PBKDF2 (600K rounds) XOR master seed HKDF-SHA256 expand secp256k1 (Nostr ID) X25519 (key agreement) Ed25519 (device certs) AES-256 (vault key) ML-KEM-768 (PQ seed)

Device Certificates

CBOR-encoded, Ed25519-signed certificates with:

Identity Merging

A person may use multiple devices (phone, laptop, tablet), each with different keys. The "merge" feature links multiple nostrPkHex values to one display name. When you send a message to a merged contact, it's encrypted and delivered to all their devices independently.

Emoji Pairing

45-emoji alphabet, visually distinct and cross-platform consistent:

🌙 ⚡ 🐬 🍀 🦋 🌊 🔥 🌸 ⭐ 🦁 🐉 🎈 🍎 🌈 🦅 🏔 🌺 🐢 🎵 🦊 🍄 🌻 🐋 🎯 🔮 🌴 🐝 🏪 🦩 🌮 🐠 🌿 🎭 🦄 🌝 🍋 🐧 🎸 🍇 🐺 🌾 🎨 🦜 🐙 🧊

6 emoji = 456 = ~8.3 billion combinations. One-time use, 24h expiry.

Nostr Event Kinds

KindPurposeEncrypted
14Direct message (inner event)Inside NIP-59
1059Gift wrap (NIP-59 outer envelope)Outer layer
10050Pairing offerSigned, public
14100Group message (inner, with session key)Inside NIP-59
25000WebRTC signal (SDP/ICE)Inside NIP-59
25001Certificate chainInside NIP-59
25002P2P DataChannel signalInside NIP-59
25003Radio voice signalInside NIP-59
25100Group call signalInside NIP-59

Local Storage

All data encrypted with AES-256-GCM using the vault key derived from identity.

IDB StoreKeyContains
identity'self' / 'all'Device identity (public keys, salt, label)
contactsnostrPkHexEncrypted contact (x25519, kem, ed25519 keys, label, tier)
sessionspeerNostrPkHexDouble Ratchet state per peer
messagesidEncrypted messages (indexed by peer and time)
groupsgroupIdGroup metadata (name, members, keys)
merged_contactsmergedIdIdentity merge records (displayName, deviceKeys)

Cryptographic Primitives

PrimitiveLibraryUse
secp256k1 (Schnorr BIP-340)k256 / libsecp256k1Nostr event signing
X25519x25519-dalekECDH key agreement
Ed25519ed25519-dalekDevice certificate signatures
ML-KEM-768ml-kemPost-quantum key encapsulation
ChaCha20-Poly1305chacha20poly1305AEAD encryption (messages, ratchet)
AES-256-GCMWeb Crypto APILocal vault encryption, group session keys
SHA-256sha2Hashing, event IDs
HKDF-SHA256hkdfKey derivation from shared secrets
PBKDF2-SHA256pbkdf2PIN stretching (600,000 rounds)
Argon2argon2Password hashing (planned)

WebRTC

1:1 Calls

Group Calls

Radio Mode

Two Client Modes

FeatureWASM (index.html)Lite (lite.html)
Crypto engineRust/WASM@noble/curves (JS)
ML-KEM-768YesNo
InteroperableYes -- hybrid encryption falls back to classical when KEM key absent
Bundle size~550 KB WASM + ~100 KB JS~128 KB JS
Works offlineYes -- Service Worker caches all assets

Relay Privacy Guarantees

WhatRelay seesWhy
Message plaintextNothingChaCha20-Poly1305 AEAD
Real sender pubkeyNothingNIP-59: fresh ephemeral key per message
Real recipient pubkeyNothingRecipient address inside encrypted envelope
Social graphNothingNo persistent keys in outer events
Call initiationNothingSDP offers are sealed events, identical to messages
Message timingApproximateTimestamps randomized +/- 5 minutes
Number of messagesYesCannot be hidden without mix network
Transparency commitment: Every cryptographic operation is implemented in open-source Rust (auditable WASM) or open-source JavaScript. No obfuscation, no telemetry, no analytics, no server-side processing. The complete source code is available for audit.

Test Coverage

MIT License. Built for privacy.