|Anthony Wang 13c3fbab94|
Kela is a new decentralized web protocol to make it easier for anyone to build and run decentralized web applications. It's basically a mishmash of ideas from ActivityPub, SMTP email, IPFS, BitTorrent, RSS, Nostr, the AT Protocol, and Spritely, but without the headaches of those existing protocols.
One popular decentralized web protocol these days is ActivityPub, which is used by Mastodon and many other applications. ActivityPub is an incredibly flexible protocol, but it also has plenty of flaws. It doesn't have replicated, fault-tolerant storage so your data can be lost due to a server shutdown or ban. Also, usernames in ActivityPub include the domain name of your server, so you can't easily migrate your account from one server to another. Implementing ActivityPub is no fun either since it uses some complicated Semantic Web stuff.
Nostr is another popular decentralized web protocol, except it doesn't really work. Instead of having a name resolution system, in Nostr you just try messaging a bunch of servers that might have information about a specific user and hope for the best. Also, Nostr is focused primarily on messaging and isn't suitable for building decentralized web applications.
Purely peer-to-peer protocols like IPFS suffer from being way too complex and slow, so that's no good either.
Alright, let's solve all those problems above with Kela! Kela consists of three components, a name resolution service using a DHT, a storage service, and a message service.
Name resolution service
In Kela, each user has an ID, which is an Ed5519 public key encoded in URL-safe Base64. Each user is associated with one or more Kela servers, which store that user's data. To find out which servers a user is associated with, you can query the name resolution system, which acts as a configuration service for the storage and message services. All Kela servers participate in the name resolution system and act as DHT nodes. Each server stores a complete list of all DHT nodes. When a new server joins the DHT, it tries to peer with an existing server in the DHT. Say server
example.com would like to peer with
example.com first sends a GET request to
test.net replies with its list of DHT nodes. Once
example.com receives this reply, it adds
test.net to its list of DHT nodes and attempts to peer with all servers in the reply that it hasn't peered with yet.
test.net now also tries to peer with the server that just contacted it, in this case
example.com. Servers periodically go through their list of DHT nodes and remove nodes that are no longer online.
The DHT stores key-value pairs. The key consists of a user's public key and timestamp (the current Unix time in seconds divided by 600, rounded down). The value consists of a timestamp (the current Unix time in seconds), a list of servers that the user is associated with, where the first server is their primary server, and a signature. A key-value pair is assigned to the 5 servers with smallest SHA-256 hashes of their domain name greater than the SHA-256 hash of the key. This allows the DHT to tolerate most of the servers failing, as long as 1 of the 5 servers is still online. The purpose of the elaborate timestamp in the key is to ensure that the set of servers assigned to a key-value pair rotates every 600 seconds so an attacker must control a very large portion of the DHT to do a denial-of-service attack against a specific key-value pair. When servers join and leave the DHT, the servers that a user is associated with will ensure that that user's key-value pair is assigned to a new server if necessary to ensure that 5 servers store that key-value pair. The DHT supports two operations, get and post. For post operations, the server checks the signature to ensure the validity of the request. When a server receives either of these two operations, it computes the SHA-256 hash of the key and checks if it is supposed to store that key-value pair or not. If it is supposed to store that key-value pair, it performs the operation on that pair. Otherwise, the server will contact in parallel the 5 servers that store this key-value pair. If the operation is a get, the server will look at the 5 replies and return the value with the most recent timestamp. If the operation is a post, and one of the 5 parallel requests fails, the server will remove that offline server from its DHT node list and assign a new server to this key-value pair to replace the offline one. Each server periodically goes through its stored key-value pairs and deletes old ones.
The storage service uses a weaker form of primary-backup replication instead of a DHT for better performance. The storage service supports two operations get and post, and a user's primary server always handles operations. Get operations are directly read the file from disk. For a post operation, the primary makes the modification and notifies all the backups about the operation, but responds to the user immediately without ensuring that the backups have performed the operation. All operations are stored in a log, which only stores the filename of the modified file, but not the contents of the operation. The log and files are persisted to disk. If a backup is behind, the backup replies to operations with its current log length and the primary will send any missing log entries. If a backup is offline, the primary will keep retrying requests. If the primary is offline, no progress can be made, but the user can designate any of the backups as the new primary, which also requires a updating the user's list of servers in the DHT. When a backup becomes a primary, it must ensure that any other backups that are ahead of this one roll back their operations to match this backup. To roll back a post operation, a backup can contact the new primary to get a correct copy of the file.
The message service allows you to send arbitrary signed HTTP requests to other users. These messages are ephemeral. If the recipient is not online, then the message fails. In Kela, applications are users too and have a public key. They are functionally equivalent to automated users. To host a website over Kela, you can create an application and make that application listen to incoming messages and tunnel them over WebSockets to a website hosted locally on your computer. Even better, Kela can replace your website's authentication system so you don't need passwords anymore! If you want to build a messaging app using Kela, you need a different design, kind of like RSS. Basically, you have a file containing messages that you have sent to the other person, and they periodically fetch that file to see your messages.
A few core ideas for Kela were braindumped by Anthony Wang on the fediverse in April 2022 and written down in a repository. A few months later, Anthony Wang and Alek Westover developed a very basic prototype during HackMIT 2022. The name "Kela" comes from spelling "Alek" backwards. The current design and implementation was written by Anthony Wang and Daniel Wang for a project for the MIT Distributed Systems class.