Loom is a Tauri and Rust desktop messaging client exploring local network discovery, direct peer-to-peer communication, cryptographic identity, and message exchange without a central messaging server.
The current implementation is designed around local-first operation. It does not use user accounts, telephone registration, a central messaging service, or cloud relay infrastructure. Peers exchange Loom identity tokens out of band, discover one another through mDNS when available, and communicate over direct TCP connections.
Loom is experimental software. It has not been independently audited and should not be treated as production-ready security software.
The repository contains a custom cryptographic protocol implementation using X25519 key agreement, Ed25519 signatures, HKDF-SHA256 key derivation, ChaCha20-Poly1305 message encryption, and a custom Double Ratchet-style state machine. Loom should not be used for high-risk, sensitive, regulated, or adversarial communications.
- Generates a local cryptographic identity from a 32-byte master seed.
- Exports public identity material as a
LOOM-token. - Imports contacts from Loom tokens.
- Discovers local peers through mDNS using
_loom._tcp.local.. - Opens a direct TCP listener on an ephemeral local port.
- Supports manual peer address injection for loopback and local testing.
- Performs signed handshake messages before chat.
- Encrypts message payloads in transit after a ratchet session is established.
- Persists contacts, message history, local identity seed, and ratchet state in SQLite.
- Exposes a Tauri desktop UI for onboarding, contact management, peer discovery, handshakes, and chat.
Loom is split into three main layers.
The frontend lives in src/ and is implemented with HTML, CSS, and JavaScript.
src/index.htmldefines the single-page application shell.src/style.cssdefines the desktop UI styling.src/main.jshandles UI state, Tauri command calls, contact rendering, peer rendering, chat rendering, and event listeners.
The frontend invokes Tauri commands such as generate_new_identity, start_network, add_contact_token, initiate_chat_handshake, send_message, and get_messages. It listens for backend events including peer_discovered, message_received, session_established, and log.
The Tauri backend lives in src-tauri/.
src-tauri/src/main.rsinitializes the app, creates theLoomEngine, registers Tauri commands, and forwards core callbacks into frontend events.src-tauri/tauri.conf.jsondefines the desktop app configuration.src-tauri/capabilities/default.jsondefines the app capability permissions.
The backend stores the SQLite database under Tauri's app data directory. The default database filename is loom.db. A LOOM_PROFILE environment variable or --profile / -p argument changes the database filename to loom_<profile>.db.
The Rust core lives in crates/loom-core/.
src/lib.rsexposes theLoomEngineAPI and callback interface.src/token.rsimplements Loom token serialization and parsing.src/storage.rsimplements SQLite persistence.src/network.rsimplements mDNS discovery, TCP transport, handshake handling, message send and receive paths, and connection tracking.src/protocol.rsdefines handshake and encrypted envelope wire messages.src/crypto.rsimplements key derivation, symmetric encryption helpers, and Double Ratchet-style session state.
Loom currently models identity as an Ed25519 public key and an X25519 public key encoded into an out-of-band Loom token. Private key material is derived from a locally generated master seed.
The implementation signs handshake payloads with Ed25519, derives shared session material from X25519 Diffie-Hellman outputs using HKDF-SHA256, initializes a Double Ratchet-style session, encrypts message payloads with ChaCha20-Poly1305, and signs encrypted chat envelopes with Ed25519.
These are implementation details, not audit results. The security model remains experimental.
- The protocol is custom and unaudited.
- Loom is not equivalent to Signal.
- SQLite stores plaintext message history after decryption.
- SQLite stores the local master seed and serialized ratchet state without application-level encryption.
- Tauri Content Security Policy is currently set to
null. - mDNS exposes local presence and network metadata on the local network.
- There is no documented identity revocation, key rotation, or recovery model.
- There is no documented key verification ceremony beyond out-of-band token exchange.
- TCP frame lengths are accepted from the network without an explicit maximum in the current implementation.
- Desktop shell: Tauri 2
- Frontend: HTML, CSS, JavaScript
- Backend: Rust
- Async runtime: Tokio
- Storage: SQLite through
rusqlite - Peer discovery:
mdns-sd - Cryptography crates:
ed25519-dalek,x25519-dalek,chacha20poly1305,hkdf,sha2,blake2,rand - Serialization:
serde,serde_json - Message identifiers:
uuid
The repository is a Rust workspace with two members:
crates/loom-coresrc-tauri
Prerequisites:
- Rust toolchain
- Node.js and npm for invoking the Tauri CLI through
npx
Run the Rust test suite:
cargo testStart the Tauri app in development mode:
npx @tauri-apps/cli devFor local multi-instance testing, run separate profiles:
$env:LOOM_PROFILE="peer1"
npx @tauri-apps/cli devOpen a second terminal in the same repository directory. If you use twin, you can open a matching terminal session from the current working directory:
twinThen run the second profile:
$env:LOOM_PROFILE="peer2"
.\target\debug\loom-backend.exeAdditional security documentation:
Loom is licensed under the MIT License.
Built by Aanish Farrukh.
Repository: github.com/sudoaanish/loom