Back to projects
Rust

orinox

Decentralized P2P chat with E2EE, resumable file transfers, and a terminal UI built on libp2p.

Rustlibp2pE2EETUICryptography

Orinox - Decentralized P2P Chat

Orinox is a single-binary, decentralized peer-to-peer (P2P) chat application written in Rust and powered by libp2p. It features a fullscreen terminal user interface (TUI) built with ratatui, End-to-End Encrypted (E2EE) direct messages, and robust, chunked P2P file transfers with automatic resumption.

                  +-----------------------------------+
                  |            Orinox TUI             |
                  |  [Rooms List]    [Chat Area]      |
                  |  [Peers List]    [Input field]    |
                  +-----------------------------------+
                                    |
                                    v
                           [Local Chat State]
                           /                \
                          /                  \
                         v                    v
                 [Storage Engine]      [libp2p Swarm]
              (.orinox/ JSON/JSONL)    /     |      \
                                      /      |       \
                                 [mDNS]  [Kademlia]  [Gossipsub]

Architecture Overview

Orinox compiles into a single executable that bootstraps a local peer identity, spins up a libp2p swarm composed of multiple cooperative network behaviors, and runs a responsive event loop driven by both network events and user input.

graph TD
    subgraph Orinox Node
        TUI[Ratatui UI] <--> State[Chat State]
        State <--> Storage[JSON/JSONL Storage]
        Swarm[libp2p Swarm] <--> State
        
        subgraph libp2p Swarm Behaviours
            Gossipsub[Gossipsub Pub/Sub]
            mDNS[mDNS Discovery]
            Kademlia[Kademlia DHT]
            ReqResp[Request-Response JSON]
            Identify[Identify Protocol]
            RelayDCUtR[Relay Client & DCUtR]
        end
    end
    
    Gossipsub <-->|Broadcast Message / File Offer| Network((p2p Network))
    mDNS <-->|Local Discovery| Network
    Kademlia <-->|Peer Routing / Find Peer| Network
    ReqResp <-->|Chunked File Transfer| Network

Features

๐Ÿ’ป Fullscreen Terminal User Interface (TUI)

  • Built using ratatui and crossterm.
  • Left sidebar displays subscribed Rooms (active room highlighted in bold yellow) and active Peers (displaying aliases if set).
  • Main view shows a timestamped, scrollable message feed with sender coloring (Green for you, Cyan for others, Red for system events).
  • Keyboard navigation:
    • PageUp / PageDown: Scroll through chat message history.
    • Up / Down arrows: Cycle through terminal command history.
    • Esc: Instantly quit the application.

๐Ÿ›ก๏ธ End-to-End Encrypted (E2EE) Direct Messages

  • Private chat over deterministic topic channels (dm-<peerA>-<peerB>).
  • Cryptographic key exchange via Diffie-Hellman (ECDH) over X25519 derived from the nodes' Ed25519 peer identities.
  • Symmetric payload encryption with ChaCha20Poly1305 authenticated encryption (AEAD).
  • Local storage and transit payloads are fully encryptedโ€”only the recipient can decrypt the message.

๐Ÿ“Ž Chunked File Sharing & Resumption

  • Offer files of any size (up to 1 GiB) via /send <path>.
  • Files are assigned a unique, random 32-character hexadecimal file_id and advertised via Gossipsub.
  • Downloads are executed via a custom libp2p request_response protocol over 64 KiB chunks.
  • If a download is interrupted, Orinox automatically aligns to the nearest completed 64 KiB block on disk and resumes from the exact point of interruption.

๐Ÿ›œ Network & Routing Stack

  • mDNS: Zero-configuration local network peer discovery.
  • Kademlia DHT: Distributed routing for connecting peers across different networks/NATs.
  • Gossipsub: Pub/Sub broadcasting of room chats, membership updates, and file advertisements.
  • Relay Client / DCUtR: Direct connection utilities and relay support for NAT traversal.
  • Identify: Self-reporting protocol matching peer versions and supported protocols.

๐Ÿ“ Persistent State Storage

Saved entirely under the .orinox/ folder in the project's working directory:

  • identity.key: Protobuf-encoded cryptographic Ed25519 keypair.
  • history_*.jsonl: Local chat transcript logs saved in JSON Lines format.
  • rooms.json: Persistent list of joined chat rooms.
  • blocked.json: List of ignored/banned Peer IDs.
  • aliases.json: Assigned names mapping to raw peer IDs.
  • received_files/: Standard directory where completed file transfers are stored.
  • received_files/.tmp_<file_id>: Temporary write locations for active file downloads.

Installation & Setup

Requirements

  • Rust Toolchain (2024 Edition compatible, Rust 1.85+)

Building from Source

# Clone the repository
git clone https://github.com/LikhinMN/orinox.git
cd orinox

# Build the release binary
cargo build --release

The compiled binary will be available at ./target/release/orinox.


Quick Start (Local Multi-Node Testing)

Run a local network using separate workspaces or ports:

Node 1 (Bootstrap Node)

Start the first node listening on port 9001 with a custom username:

cargo run -- --port 9001 --name Alice

Node 2 (Connect to Alice)

Start a second node, connect directly to Alice, and discover others:

cargo run -- --port 9002 --connect /ip4/127.0.0.1/tcp/9001 --name Bob

Command Line Options

orinox [OPTIONS]
ShortLongValueDescription
-p--portPORTPort to listen on (default: 9000)
-c--connectMULTIADDRAddress of a peer to dial (can be specified multiple times)
-b--bootnodesMULTIADDRKademlia DHT bootnodes to bootstrap routing table
-n--nameSTRINGUsername displayed in chat (defaults to auto-generated user_<short_id>)
-l--log-levelLEVELSet output logging level: error, warn, info, debug, trace (default: info)
-h--help-Print help information
-V--version-Print version information

In-Chat Command Reference

Type any command in the input bar at the bottom right of the TUI:

CommandUsageDescription
/help/helpList all available in-chat commands and keybindings
/name/name <new_name>Change your local username
/join/join <room_name>Join and switch view to a specific room
/leave/leaveLeave the current room and return to the global room
/rooms/roomsList all rooms you have joined
/current/currentDisplay the active room name
/peers/peersPrint all currently connected peers in the main log
/alias/alias <peer_id> <name>Assign a friendly name/alias to a Peer ID
/aliases/aliasesList all active aliases
/dm/dm <peer_id_or_alias> <msg>Send an End-to-End Encrypted (E2EE) direct message
/send/send <file_path>Offer a file for other peers to download
/download/download <file_id_prefix>Start/resume download of an offered file by ID
/history/history [N]Print the last N messages from the room's persistent history
/ban/ban <peer_id_or_alias> [reason]Block and ignore incoming chat messages from a peer
/unban/unban <peer_id_or_alias>Unblock a banned peer
/bans/bansList all banned peer IDs
/exit/exitGracefully quit the application

Protocol & Formats

1. Chat Message Format (Gossipsub JSON)

Messages broadcasted over Gossipsub are serialized as JSON:

{
  "username": "Alice",
  "message": "Hello world!",
  "timestamp": 1782348923000,
  "file": null
}

2. Encrypted Direct Message Format (E2EE DM)

DMs are sent to a private topic hash derived from sorting both peer IDs. The payload consists of:

  • A 12-byte initialization vector (nonce) prepended to the ciphertext.
  • The ChaCha20Poly1305 encrypted bytes of the standard Gossipsub JSON message.

3. File Transfer Protocol

  • Offered File Announcement: Sent via Gossipsub with data set to null and a unique file_id populated:
    {
      "username": "Alice",
      "message": "๐Ÿ“Ž Offered file: document.pdf",
      "timestamp": 1782348923000,
      "file": {
        "filename": "document.pdf",
        "size": 142048,
        "file_id": "8bfa2e12a456...",
        "data": null
      }
    }
    
  • Chunk Request/Response: Initiated over libp2p request_response (JSON serialization):
    // Request
    { "file_id": "8bfa2e12a456...", "chunk_index": 2 }
    
    // Response
    { "file_id": "8bfa2e12a456...", "chunk_index": 2, "data": [ ... ], "is_last": false }
    

Development & Testing

Run verification suites and ensure formatting and clippy lints pass:

# Run unit and integration tests (including crypto & lifecycle)
cargo test

# Check code formatting
cargo fmt --check

# Run lints
cargo clippy -- -D warnings

License

This project is licensed under the terms specified in the Cargo.toml file.