Minimal, Tor-capable, peer-to-peer, end-to-end encrypted chat for the terminal.
- No central server
- One-on-one only (no groups, no history)
- Identities = Ed25519 keys, stored encrypted on disk
- Optional Tor hidden services (
.onion) for metadata protection - Optional personal phrase to silently signal in-person compromise
This is intentionally small, boring, and opinionated.
- 🔐 End-to-end encryption using X25519 + ChaCha20-Poly1305
- 🆔 Identities are Ed25519 keypairs derived from a 32-byte seed
- 💾 Seed is never stored in plaintext – the identity file is password-encrypted
- 👥 Contacts are simple JSON files you exchange out-of-band. You can only connect tocontacts if you have their contact cards stored.
- 🧅 Optional Tor hidden services for incoming connections
⚠️ Optional personal duress phrase to signal “something is wrong with me” to a trusted contact
No groups, no media, no typing indicators, no push notifications.
- Rust (stable) and Cargo
- Tor daemon (
tor) if you want.onionsupport- On Debian/Ubuntu:
sudo apt install tor - On macOS (Homebrew):
brew install tor
- On Debian/Ubuntu:
git clone https://github.com/yourname/p2pchat.git
cd p2pchat
cargo build --release
# or: cargo install --path .Assume the binary is available as p2pchat.
- Initialize your identity
p2pchat initYou will be asked to choose an identity password. This encrypts your private seed on disk.
You’ll see your public key, and optionally you can:
- configure a Tor hidden service,
- then set your onion address:
p2pchat id-set-onion abcdef1234567890.onion:9000- Export your contact card
p2pchat contact-export --name "Your Name" > mycard.jsonSend mycard.json to your friend via some secure out-of-band channel.
- Add a friend’s contact
When you receive bob_card.json from your friend:
p2pchat add-contact bob bob_card.jsonCheck your contacts:
p2pchat contact-list- Bob listens
On Bob’s side:
p2pchat listen
# default: 127.0.0.1:9000 (behind Tor hidden service if configured)If Bob has set up a Tor hidden service forwarding to 127.0.0.1:9000, the .onion:9000 address should be in his contact card already.
- Alice connects
On Alice’s side:
p2pchat connect-alias bobBehavior:
If Bob has an onion address and Tor SOCKS is reachable at 127.0.0.1:9050, p2pchat connects over Tor.
Otherwise you can override with a direct TCP address:
p2pchat connect-alias bob --addr 127.0.0.1:9000Once connected, you’ll see:
- which contact you’re talking to (by alias),
- whether their identity matches what you have on file,
- whether their personal phrase check passes (if configured).
- Personal duress phrase (optional)
You can set a personal phrase that is only used to signal in-person compromise:
p2pchat id-set-passphraseOn each connection, your app:
- silently asks you for this phrase,
- never tells you whether it matched, but sends a simple status (OK / FAILED / NotConfigured) to the peer.
If you intentionally type something wrong (or just press Enter), the other side will see a big warning:
“Peer personal phrase verification FAILED. They may be compromised or under duress.”
This provides a human-layer signal on top of the cryptographic identity.
- The identity seed is encrypted on disk using a key derived from your password with Argon2id and ChaCha20-Poly1305.
- If your device is compromised and the attacker learns your identity password, your cryptographic identity is compromised.
- This tool does not attempt to provide perfect anonymity or metadata protection by itself: for that, you should use Tor hidden services and .onion addresses. There is no message history: once both sides close the session, messages are gone unless you log the terminal yourself.
This project is meant as a minimal, auditable toy / learning tool and a possible basis for more serious experiments.
This project is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.