Overview

Ping
Zero-Knowledge
Encrypted Messaging

Largest anonymity set of any P2P messenger. Own the silence.

Encryption & Identity

Every message is encrypted client-side before touching any relay.
Ping never sees plaintext. Keys never leave the device.

X25519 HKDF-SHA256 ChaCha20-Poly1305 Nostr Event
Key agreement → Key derivation → Authenticated encryption → Transport

X25519 Key Exchange

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.

ChaCha20-Poly1305

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.

Message Padding

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.

Privacy Envelopes

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.

Sender Keys (Group Encryption)

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.

Nostr / Schnorr Identity

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.

Zero-Knowledge Design

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.

🛡️ Zero-Knowledge Design Principles

  • Ping never has access to message plaintext, all encryption and decryption is client-side
  • Relay operators see only encrypted blobs with Nostr event metadata
  • File sharing URLs embed decryption keys in the URL fragment, never sent to server
  • Session authentication uses HMAC-SHA256 tokens, no client code transmitted on auth
  • Key fingerprints enable out-of-band identity verification between peers
  • Private keys encrypted at rest with PIN or biometric-derived keys
  • No message logs on any server, conversations exist only on participant devices

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.

The Data-at-Rest Inversion Every other messenger, including privacy-focused ones, creates data and then builds defenses around it. Signal's Double Ratchet protects a message archive that lives on your device. WhatsApp's encryption protects messages that may live in an unencrypted cloud backup. Ping's primary defense is the absence of the data itself. The encryption protects messages in transit. The ephemeral architecture ensures there is nothing to protect at rest. You don't need a lock on a door that doesn't exist.

They built bigger locks. We eliminated the room.

Ping · Design Philosophy

Session Security

Private keys are encrypted at rest and protected by configurable local authentication.

PIN Lock

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.

WebAuthn Biometric

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.

Identity Encryption at Rest

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.

Session Export / Import

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.

Network & Relay Layer

Multi-relay WebSocket architecture with automatic failover, health monitoring, and configurable topology.

Multi-Relay Mesh

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.

Exponential Backoff Reconnect

Disconnected relays auto-reconnect with jittered exponential backoff (1s → 60s cap). Jitter prevents thundering herd on network recovery. All timing parameters are user-configurable.

Health Monitoring

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.

Outbound Queue

Messages sent while offline are queued (up to 50) and automatically flushed when any relay reconnects. Queue prevents message loss during brief network interruptions.

Relay Diagnostics

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.

Advanced Network Config

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.

Deduplication

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.

EOSE Tracking

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.

Chat Features

Full-featured encrypted messaging with rooms, DMs, reactions, and media.

Multi-Room Support

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.

Encrypted DMs

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.

Disappearing Messages

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.

Ephemeral by Default

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.

Delivery Receipts

Privacy-enveloped delivery confirmations (type 6) sent on message receive. Displayed as checkmarks on sent messages. Routed via the pairwise encryption path.

Reactions & Emoji

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.

Typing Indicators

Real-time typing status broadcast (kind 4247) with debounced transmission and automatic expiry. Displayed as animated dots below the message list.

Message Persistence

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.

Message Search

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.

Reply Threading

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.

Built-in Tools

Standalone encrypted utilities accessible from the tools tab or the quick-tools picker in chat.

Manuscrypt (Encrypt)

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.

URL Shortener

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.

QR Code Generator

Generate QR codes for any text or URL. Client-side rendering. Send directly to chat or DM. Supports error correction and custom sizing.

UX & Interface

Telegram-native design language with dark-first theming, gesture controls, and mobile-optimized layouts.

Theme Engine

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.

Responsive Typography

Four text size presets (S/M/L/XL) with a segmented control. Font sizing cascades through CSS custom properties affecting all UI elements proportionally.

Telegram WebApp Integration

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.

Gesture Controls

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.

Keyboard Management

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.

Settings Architecture

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.

Developer Settings

Debugging tools, protocol tuning, and experimental feature flags for development and power users.

Verbose Logging

Toggle colored console logging for relay connect/disconnect, event publish/receive, and cryptographic key derivation. Category-prefixed output ([relay], [crypto]) for easy filtering.

Live Event Log

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.

Copy Debug Info

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.

Protocol Tuning

Configurable render window, outbound queue size, and deduplication buffer capacities. Message padding can be disabled for testing. Changes persisted to localStorage.

Storage Inspector

localStorage usage breakdown by category with byte sizes. Per-room message counts and sizes. Individual room clear buttons without wiping the full session.

Config Sync & Feature Flags

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.

System Architecture

A minimal two-tier design: a zero-dependency client and a minimal server that never sees plaintext.

Client

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.

Service

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.
CLI operates independently.

Transport

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.

Persistence

IndexedDB (primary) + localStorage (fallback) for messages. localStorage for identity (encrypted), theme, config, drafts, topics. Automatic migration from legacy flat-key storage to namespaced scheme.

Back to home