The goal of this document is to describe how group chats (a.k.a. swarm chat) will be implemented in Jami.
A swarm is a group able to discuss without any central authority in a resilient way. Indeed, if two person doesn't have any connectivity with the rest of the group (ie Internet outage) but they can contact each other (in a LAN for example or in a sub network), they will be able to send messages to each other and then, will be able to sync with the rest of the group when it's possible.
So, the swarm is defined by:
Ability to split and merge following the connectivity.
Syncing of the hitory. Anyone must be able to send a message to the whole group.
No central authority. Can't rely on any server.
Non-repudiation. Devices must be able to verify old messages validity and to replay the whole history.
PFS on the transport. Storage is managed by the device.
Main idea is to get a synchronized merkle tree with the participants.
Create a Swarm
Bob wants to create a new swarm
Bob create a local git repository.
Then, he adds an initial signed commit and adds the following:
His public key in /admins
His device certificate in ̀ /devices`
His CRL in ̀ /crls`
The hash of the first commit becomes the ID of the conversation
Bob announce to his other devices that he creates a new conversation. This is done via an invite to join the swarm sent through the DHT to other devices linked to that account.
Receiving an invite
Alice gets the invite to join the previously create swarm
She accepts the invite
A peer to peer connection between Alice and Bob is done.
Alice pull the git repo of Bob. WARNING this means that messages needs a connection, not from the DHT like today
Alice validates commits from Bob
Once all commits validated and on her device, other members of the group are discovered by Alice. with these peers, she will construct the DRT (explained below) with Bob as a bootstrap.
Sending a message
Alice sends a message
Sending a message is pretty simple. Alice write a commit-message with the following format:
TODO format unclear
and adds her device and CRL to the repository if missing (others must be able to verify the commit). Merge conflicts are avoided because we are mostly based on commit messages, not files (unless CRLS + certificates but they are located). then she announce the new commit via the DRT with a service message (explained later) and ping the DHT for mobile devices (they must receive a push notification).
Receiving a message
Bob receives the message from Alice
Bob do a git pull on Alice
Commits MUST be verified via a hook TODO describe the process for validation
If all commits are valid, commits are stored and displayed. Then Bob announce the message via the DRT for other devices.
If all commits are not valid, pull is cancelled. Alice must restablish her state to a correct state. *TODO process
Ban a device
Alice, Bob, Carla, Denys are in a swarm. Alice bans Denys
This is one of the most difficult scenario in our context. Without central authority we can't trust:
Timestamps of generated commits
Conflicts with banned devices. If multiple admin devices are present and if Alice can speak with Bob but not Denys and Carla ; Carla can speak with Denys ; Denys bans Alice, Alice bans Denys, what will be the state when the 4 members will merge the conversations.
A device can be compromised, stolen or its certificate can expire. We should be able to ban a device and avoid that it lies about its expiration or send messages in the past (by changing its certificate or the timestamp of its commit).
Similar systems (with distributed group systems) are not so much, but this is some examples:
Signal, without any central server for group chat (EDIT: they recently change that point) doesn't give the ability to ban someone of a group.
Moreover, to advance in the time there is only two methods. Time (that we can't trust here because not common and provable) or ordered sequences (2 is after 1. 3 after 2, etc).
So, to ban a device, we have to add 2 points:
Each message must be ordonned without the possibility to have a gap between two messages. So each device must signal its sequence number which has to be validated with previous messages.
Each group members have to know from which sequence number a device is banned and considered as invalid. Because the authority of a swarm is distributed, a voting system (with more than 50% of admin devices must get a consensus) should be implemented to decide when a sequence number for a device is considered as invalid.
This voting system need a human action to ban someone or must be based on the CRLs infos from the repository (because we can't trust external CRLs)
So, if Alice wants to ban Denys, she had to propose a vote with the sequence number of the device (0 for future devices).
TODO, determine how this will work
Why this choice
Each conversation will be a git repository. This choice is motivated by:
We need to sync and ordering messages. The Merkle Tree is the perfect structure to do that and can be linearized by merging branches. Moreover, because it's massively used by Git, it's easy to sync between devices.
Distributed by nature. Massively used. Lot of backends and plugguable.
Can verify commits via hooks and massively used crypto
Can be stored in a database if necessary
Conflicts are avoided by using commit messages, not files.
What we have to validate
Performance? git.lock can be low
Hooks in libgit2
Multiple pulls at the same time?
History can't be deleted. To delete a conversation, the device has to leave the conversation and create another one.
However, non permanent messages (like messages readable only for some minutes) can be sent via a special message via the DRT (like Typing or Read notifications).
Moreover editing messages will be possible! (commit --fixup)
/ - Admins (public keys) - Members (public keys) - Devices (certificates of authors to verify commits) - Banned - Devices - Accounts - CRLs
Avoid git bombs
Timestamp of a commit can be trusted because it's editable. Only the user's timestamp can be trusted.
Git operations, control messages, files and other things will use a p2p TLS v1.3 link with only cyphers which garanty PFS. So each key is renegotiated for each new connexion.
Used to send messages for mobiles (to trigger push notifications) and to initiate TCP connexions.
DRT (name will change)
The DRT is a new concept used in swarm to maintain p2p connections. Indeed, group members define a graph of nodes (identified by a hash) en must be connected.
So we need a structure that:
Maximize the connected nodes at every time
Minimize the time for message transmission
Minimize links between peers
Needs low calculation
Several solutions exists:
Each node has a connection to the next node. So we only need $N$ connections, but it's not effective to transmit a message, because the message will go though all peers, one by one.
Each nodes is connected to all other nodes $N\timesN$ connections. Effective to transmit, but need more resources WILL BE CHOSEN FOR THE FIRST VERSION
Use the algorithm of the DHT for the routing table. The 4 points are basically solved and already used by Jami in UDP.
Note: to optimize the socket numbers, a socket will be given by a ConnectionManager to get multiplexed sockets with a given hash. This means that if we need to transmit several files, and chat with someone, only one socket will be used.
File transfer (libtorrent?)
!! OLD DRAFT !!
Note: Following notes are not organized yet. Just some line of thoughts.
For a serious group chat feature, we also need serious crypto. With the current design, if a certificate is stolen as the previous DHT values of a conversation, the conversation can be decrypted. Maybe we need to go to something like Double ratchet.
Note: a lib might exists to implement group conversations. TODO, investigate.
Needs ECC support in OpenDHT
There is two major use case for group chats:
Something like a Mattermost in a company, with private channels, and some roles (admin/spectator/bot/etc) or for educations (where only a few are active).
Horizontal conversations like a conversation between friends.
Ring will be for which one?
A certificate for a group which sign user with a flag for a role. Adding or revoking can also be done.
Join a conversation
Only via a direct invite
Via a link/QR Code/whatever
Via a room name? (a hash on the DHT)
What we need
Confidentiality: members outside of the group chat should not be able to read messages in the group
Forward secrecy: if any key from the group os compromised, previous messages should remain confidential (as much as possible)
Message ordering: There is a need to have messages in the right order
Synchronization: There is also a need to be sure to have all messages at soon as possible.
Persistence: Actually, a message on the DHT lives only 10 minutes. Because it's the best timing calculated for this kind of DHT. To persist datas, the node must re-put the value on the DHT every 10 minutes. Another way to do when the node is offline is to let nodes re-put the data. But, if after 10 minutes, 8 nodes are still here, they will do 64 requests (and it's exponential). The current way to avoid spamming for that is queries. This will still do 64 requests but limit the max redundency to 8 nodes.
Other distributed ways
IPFS: Need some investigation
BitMessage: Need some investigation
Maidsafe: Need some investigation
Based on current work we have
Groups chat can be based on the same work we already have for multi devices (but here, with a group certificate). Problems to solve:
History sync. This need to move the database from the client into the daemon.
If nobody is connected, the synchronization can't be done, and the person will never see the conversation