Largest anonymity set of any P2P messenger. Own the silence.
Every message is encrypted client-side before touching any relay.
Ping never sees plaintext. Keys never leave the device.
Each user generates an X25519 keypair on first launch. Shared secrets are derived via Diffie-Hellman and fed into HKDF-SHA256 with a room-scoped salt, producing unique per-peer symmetric keys.
All message content is encrypted with ChaCha20-Poly1305 AEAD, providing both confidentiality and integrity. Each message uses a fresh 12-byte random nonce. Implemented via a WebWorker crypto pool for non-blocking performance.
Messages are padded to predefined bucket sizes (256B → 512KB) before encryption, preventing traffic analysis from inferring message length. Buckets follow a power-of-two scheme to minimize overhead.
Sensitive operations (DMs, reactions, receipts, key exchanges) are wrapped in privacy envelopes, a second encryption layer with independent HKDF derivation, typed payloads, and bucket padding, hiding both content and operation type from relays.
Rooms use a Sender Key protocol: each member generates a chain key, distributes it via pairwise X25519, then broadcasts O(1) symmetric-encrypted messages. Chain keys ratchet forward after each send (HMAC-SHA256), providing forward secrecy. Keys rotate every 100 messages or on any membership change.
User identity is a secp256k1 keypair (Nostr-compatible). Events are signed with BIP-340 Schnorr signatures, providing non-repudiation and relay-verifiable authenticity. Pure-JS implementation with no external crypto libraries.
The architecture is designed so that no entity, not Ping, not the relays, not the client,
ever has access to message content or user communication graphs.
There is no server. There is no message store. There is no plaintext outside your device. The relay cannot read what it carries. Telegram cannot see what it fronts. Ping is serverless by design. That is not a feature. That is the default.
They built bigger locks. We eliminated the room.
Ping · Design PhilosophyPrivate keys are encrypted at rest and protected by configurable local authentication.
4-digit PIN encrypts the identity at rest using PBKDF2 with 200,000 iterations + a device-bound key derived from WebCrypto. Rate-limited: 3 attempts, then 30s lockout doubling to 1 hour. Countdown displayed live.
Optional fingerprint/face unlock via WebAuthn platform authenticators. Stores a PRF-derived credential that can decrypt the identity without PIN entry. Falls back gracefully if biometrics unavailable.
Private keys in localStorage are AES-GCM encrypted with a key derived from PIN + device salt + PBKDF2. Even with device access, keys require the PIN or biometric to decrypt.
Full identity + room state can be exported as an encrypted JSON blob for device migration. Import restores the complete session including cryptographic identity and room memberships.
Multi-relay WebSocket architecture with automatic failover, health monitoring, and configurable topology.
Connects to 8 default Nostr relays simultaneously. Messages broadcast to all connected relays for redundancy. Relay selection is ranked by latency and failure count. Custom relays can be added, defaults can be disabled.
Disconnected relays auto-reconnect with jittered exponential backoff (1s → 60s cap). Jitter prevents thundering herd on network recovery. All timing parameters are user-configurable.
Periodic presence heartbeats (45s) serve dual purpose: relay liveness detection and peer presence tracking. Relays silent for 90s are marked dead and recycled. Stale peers pruned after 120s, triggering sender key rotation.
Messages sent while offline are queued (up to 50) and automatically flushed when any relay reconnects. Queue prevents message loss during brief network interruptions.
Full-screen diagnostics panel showing per-relay connection status, latency, fail count, last message age, and a one-tap "Ping All" round-trip test using Nostr REQ/EOSE cycles.
All connection parameters are runtime-configurable and persisted: backoff timing, stale timeouts, presence intervals, peer detection intervals. Relay topology (enable/disable defaults, add custom) with immediate connect/disconnect.
Two ring buffers (RingSet), 10K events and 5K messages, prevent duplicate processing when the same event arrives from multiple relays. Capacities are configurable in dev settings.
Subscription-level End-Of-Stored-Events tracking with Promise-based await. Room join waits for at least one relay to confirm historical sync before marking the room as ready.
Full-featured encrypted messaging with rooms, DMs, reactions, and media.
Join multiple rooms simultaneously with independent message streams, peer lists, topics, and sender key states. Room switching is instant, all state lives in a centralized rooms Map.
Direct messages within rooms use dedicated pairwise X25519 envelopes (kind 4246). Slide-up panel with drag-to-dismiss gesture, viewport-locked height, and per-peer thread persistence.
Per-conversation timer (30s / 5m / 1h / 24h) auto-deletes messages from the local display. Configured via a popover in the DM header. Timer badge shows active duration.
Messages exist only in memory. No conversation is saved unless you explicitly opt in. When a session ends, the message stream is gone. No database to extract, no archive to subpoena, no ciphertext to target retroactively. Persistence is the exception, not the rule.
Privacy-enveloped delivery confirmations (type 6) sent on message receive. Displayed as checkmarks on sent messages. Routed via the pairwise encryption path.
Tap-and-hold context menu for message reactions. Reactions sent as privacy-enveloped events. Full emoji picker with categorized tabs, skin tone support, and recent tracking.
Real-time typing status broadcast (kind 4247) with debounced transmission and automatic expiry. Displayed as animated dots below the message list.
Room messages persist to IndexedDB (with localStorage fallback) across sessions if enabled. Migration from legacy storage, configurable save toggle, and per-room clear from dev settings.
Real-time full-text search across the current room with result highlighting and forward/backward navigation. Search bar slides in from the top with keyboard focus management.
Tap-to-reply on any message with a quoted preview in the compose area. Reply references are embedded in the encrypted payload and rendered as linked quote blocks.
Standalone encrypted utilities accessible from the tools tab or the quick-tools picker in chat.
Client-side file encryption via the server's zero-knowledge relay. Upload → AES-GCM encrypt → get a share link with the decryption key in the URL fragment (never sent to server). Password protection optional. Expiry control.
Encrypted short URLs with configurable expiry (1h–21d) and optional password. URL destination is encrypted client-side before storage. Quick-send to current room or DM.
Generate QR codes for any text or URL. Client-side rendering. Send directly to chat or DM. Supports error correction and custom sizing.
Telegram-native design language with dark-first theming, gesture controls, and mobile-optimized layouts.
12+ preset themes with instant preview. Custom accent + background color pickers. Light/dark/auto mode with system preference detection. All theme state persisted across sessions.
Four text size presets (S/M/L/XL) with a segmented control. Font sizing cascades through CSS custom properties affecting all UI elements proportionally.
Respects Telegram safe areas, viewport insets, and content padding. Haptic feedback via Telegram SDK (light/medium/success/error). Back button navigation with deep panel awareness.
Drag-to-dismiss on DM panels with velocity-based flick detection (0.4px/ms threshold). Rubber-band resistance past 80px. Pull-to-refresh on chat list. Outside-tap dismiss for popovers.
Visual viewport height locking prevents panel resize during keyboard show/hide. Focus management with preventDefault on all non-input buttons. Auto-resize textarea grows with content up to 120px.
Telegram-style 3-level navigation: main menu → category sub-panels → deep sub-panels. Slide-in transitions with back arrow hierarchy. Six categories: Security, Session, Network, Appearance, Dev Settings, Support.
Debugging tools, protocol tuning, and experimental feature flags for development and power users.
Toggle colored console logging for relay connect/disconnect, event publish/receive, and cryptographic key derivation. Category-prefixed output ([relay], [crypto]) for easy filtering.
Real-time scrolling log of all inbound Nostr events. Color-coded kind badges (presence, key exchange, room message, DM, typing, leave). Shows relay source, timestamp, pubkey prefix, and payload size.
One-tap clipboard dump: user agent, Telegram SDK info, all relay states with latency/fails/last pong, peer list across rooms, full config snapshot, and localStorage breakdown.
Configurable render window, outbound queue size, and deduplication buffer capacities. Message padding can be disabled for testing. Changes persisted to localStorage.
localStorage usage breakdown by category with byte sizes. Per-room message counts and sizes. Individual room clear buttons without wiping the full session.
Export/import network + relay + theme + dev config as a portable JSON blob (no private keys). Named boolean feature flags with toggle/remove, accessible via devFlags.name in code.
A minimal two-tier design: a zero-dependency client and a minimal server that never sees plaintext.
Single-file application. Zero runtime dependencies. ES module with inline CSS. All crypto, UI, and state management in one deployable artifact. WebCrypto API for all primitives.
Python (aiohttp + python-telegram-bot). Minimal role: Telegram bot entry point, session authentication (HMAC-SHA256), encrypted file relay proxy, URL shortener backend. Never sees message plaintext.
Applies to the Ping Mini App only.Nostr protocol over WebSocket relays. Custom event kinds: 4242 (room message), 4243 (key exchange), 4244 (presence), 4245 (leave), 4246 (DM), 4247 (typing). Privacy envelopes wrap sensitive operations.
IndexedDB (primary) + localStorage (fallback) for messages. localStorage for identity (encrypted), theme, config, drafts, topics. Automatic migration from legacy flat-key storage to namespaced scheme.