This is what I am working on right now and could use some inspiration from the community.
i’ll break it down into steps:
- Sending/receiving messages. Probably the easiest part, use pubsub. Also encrypt and sign messages, should not be a challenge. The topic for pubsub could be the concatenation of the two participants, hashed.
- Challenge number one: what if the recipient is not online? What I came up with is that upon receipt a confirmation message is sent back. If no confirmation was received send again. Other approach is to store the unreceived message. Then require each client to announce themselves to the network whenever they come online, then when such announcement was received by the sender, resend the message. But in this case, what if the sender has gone online?
- Challenge number two: NAT problems, what if some one is sitting behind a router? I’m sure there already is a solution to this, but I haven’t had the time to look into it.
- Message storage: like any other chat app I want to be able to see past conversations. As long as the user uses just one device, this is pretty straight forward, save to disk, load from disk. Probably symmetrically encrypted. But what if later I want to log in from some other device? Then I need to fetch my past messages from my original device.
- Solution one: use FileCoin storage. I don’t want this app to cost money (FIL), so, no.
- Solution two: I could store my data on IPFS but I don’t suppose it will stay there very long as without incentive it will be garbage collected. Pinning services cost money, AND they are kinda centralized. So no.
- Solution three: store data on Ethereum blockchain as a smart contract. Again, costs money, so no good.
- Solution four: friend-to-friend ‘subnetworks’. I store your data as long as you store mine. The idea here is that there is no need for complicated, trustless verification schemes(PoS, Pow, PoSt etc etc etc), the trust is simply the trust in friends that they will host your data in exchange for you hosting theirs. From a technical point of view this can be done using OrbitDb, where friends replicate each other’s databases. This of course doesn’t guarantee 24/7 data availability, it is possible that all nodes that have my data replicated are offline. but, the more friends the better.
- Solution five: don’t bother. As in, realistically is this even a use case? How often does one find themselves logging in from some random device? Usually it’ll be like, laptop, work device, smart phone and that’s it. Occasionally exchange one of these for a newer one. My point is that if we are trying to login from some new device, chances are that we have another device on us (usually the smart phone), and therefore we can move our data (past messages) from one to the other. Like for example, encode the OrbitDB address into a QR code, scan it with the smart phone, and replicate the DB. Or, encode a random topic string into a QR code, scan it with the mobile phone, then send the DB address over that topic, and then finally the new device replicates the DB.
- If you have any better ideas PLEASE let me know.
Identity: How are users identified. This usually involves some unique identifier such as an email, a phone number, a username guaranteed by the server to be unique and so on. For the first two: I advocate for anonymity so no, for the third one, we have no server so yeah, can’t be done.
A solution I came about is seeded key pairs: instead of using a truly random number for asymmetric key generation, use a seeded CSPRNG.
The seed would be obtained by passing a passphrase to a KDF like Scrypt, with the username as salt. This way, the same private/public key could be replicated on any device, without having to import the key from another device, provided the user remembers their username and password.
It could be argued that this is less safe than truly random generated private keys, but I think it is just as safe as any other auth service right now: if somebody learns my username and password I lost my privacy.
I imagine verification of a public key belonging to a person would be done in-person, there is no better method I am aware of.
Of course, as mentioned in the section above, if I use solution five for syncing data between devices, might as well send the keypair over as part of that same process.
Finally, is it even worth it? To me it is a cool experiment, a chat app with no central choke point, for the sake of it. Nevertheless, surely it will be slower, data might not be available at times and so on