Zbay is a Mac, Windows, and GNU/Linux desktop app that uses a peer-to-peer network built on Tor, libp2p, and OrbitDB to offer a team chat experience like Slack, Telegram, or Discord. You can register a username, join public group chats, message other users, and send or receive money, without depending too much on centralized infrastructure.
Zbay's use of centralized infrastructure is already minimal and we're working on reducing it even further. First, to enable Zcash payments without a 20+ GB storage requirement for each user, we connect directly (not via Tor) to a centralized Zcash lightwallet server run by the Zecwallet project. We hope to connect to this infrastructure via Tor in the future, but it is not supported yet.
For username registration and peer discovery on startup, we currently rely on centralized infrastructure (both our own, and the lightwallet infrastructure run by Zecwallet), but our goal is to remove these dependencies in the next major release. At that point, an invite link from a community owner will be sufficient to discover peers, register a username, and join a community.
Finally, we rely on the Tor network, though this seems perfectly prudent and brings many benefits, including metadata privacy against a wide range of attackers, addresses for peers that are both permanent and unguessable, and the ability to connect any two peers regardless of NATs or firewalls.
Libp2p is the underlying p2p network layer for a growing family of well-funded projects, including Filecoin and Ethereum 2. It lets peers connect over multiple kinds of transports, including WebSockets, which work well when used with Tor. To use libp2p with Tor, we create a Tor v3 onion service for each peer, and then use a modified WebSocket transport to connect to the onion addresses of other peers.
In simple terms, each peer runs a simple webserver behind an onion address on the Tor network, and peers connect to each others' servers.
Right now, Zbay only operates on one network whose entry node is hardcoded into the app itself, so all messages are public. But this will change soon as we add the ability to create new private communities, each running on their own separate libp2p network.
We could use libp2p pubsub for broadcasting a message to all online peers in a given network. But what about peers who are offline? The magic of modern messaging apps like Slack, Discord, Telegram, and Signal (in contrast to older approaches like IRC and Pidgin/OTR) is that users don't miss messages sent while they were offline; in modern messaging apps, these messages appear almost instantly once users come back online. How do we achieve that, without a central server?
Secure Scuttlebutt addresses this problem, but it does so in a way that is very specific to a "social network feed with a single publisher" use-case (think: decentralized Twitter) and would require a lot of awkward stretching to use for a conversation with a mix of participants. The "sync all changes" functionality that Git provides is closer to what we need, and we even used Git in our prototypes! But this was a hack, and bundling Git with Zbay for several different OSes and device types would have been a massive headache.
OrbitDB ended up being pretty much exactly what we needed, and while it's still somewhat experimental and maintained by a small team, it builds on libp2p and IPFS tools that are used more widely. OrbitDB gives us an easy way for offline peers to return and fetch what they missed. We also get some limited guarantees around the integrity of messages and message ordering.
There's no way to delete data from an OrbitDB, yet. But we should be able to make messages deletable someday by linking to message content from OrbitDB (and then deleting that) or by deleting entire OrbitDBs and recreating them without the deleted messages. The details get messy, and like almost any deletion scheme it requires trusting recipients, but it is possible.
A requirement for any team chat app is the ability to start private conversations with one or more other team members. We want these messages to be eventually visible to offline peers too, since that's what users have come to expect from modern, centralized messaging apps. As sometimes happens with peer-to-peer approaches, the needs of privacy and availability pull in different directions. We believe the best balance is to broadcast private messages to all members of a community, but encrypt them to their intended recipients.
This leaves the problem of metadata privacy within the community. Currently, any member of the community can learn who is talking to whom, and when, and that is not desirable! We plan to addres this in the future by using Tor to deliver messages to the peer-to-peer network anonymously.
Our approach to "syncing missed messages" still requires that at least one peer has been online since those messages were sent. It doesn't have to the be same peer; peers can sync messages from one to the next, like relay racers passing a baton. But if no peers are online, or if there was a gap, returning users won't see those messages until a peer who did see them comes back online. That's not great! There will be an invisible gap in the conversation, with a weird UX issue once those old messages resurface again.
Our current plan for this is to build a decent Android app that can remain connected to the peer-to-peer network for as long as the phone is turned on and has service. We're currently building a prototype for Android and it's promising, but we don't know how practical this is yet. We've heard that the battery life impact of running Tor onion services in the background is manageable on new phones.
The hope is that if everyone joins the network with all of their devices, even small communities of 5-10 members will have enough always-on peers to minimize these kinds of gaps.
If this doesn't work, another approach would be to let communities add an altruistic (or perhaps a compensated) always-on peer without giving them the keys needed to decrypt messages.