Thoughts on the Spring '83 protocol draft
Jun 14th, 2022
by makeworld
Right this morning when I woke up, before I even had a glass of water, I started reading a blog post by Maya discussing a new protocol. I was immediately intrigued, and starting reading the original post, Specifying Spring ‘83. After reading through the blog post, I excitedly moved on to the actual spec draft. I was amazed. Possibly because it was the first thing my brain had processed all day, but still, I really loved the idea. What follows is some thoughts on the spec draft, to add to the ongoing discussion.
I am reviewing the spec from commit 1a37b2f,
which is from June 10, 2022.
Design
Various protocol design comments below.
YAML
Please don’t use YAML for the peer list. YAML is not great. A simple JSON list would be better. A separate Markdown file can provide human-readable metadata if needed.
Key rotation
The key rotation scheme is definitely interesting. I like the idea of limiting the damage a leaked key can do, similar to TLS cert renewal. However I think the user experience of having to generate a new key every two years and tell all your friends about it is quite bad, and will make people wonder why they have to do this. I get the idea of culling old followers, but the reality is that this is a one-way protocol will no follow notifications, so the effect of this culling won’t be felt.
One solution is to have the majority of people not actually manage their own keys, but that doesn’t feel great either. I think it would probably be better to just let keys stick around with no expiry. This seems to have worked out okay for Scuttlebutt.
Server-to-server communication
First off, it’s not explicitly mentioned that one server sending a board to another triggers that server to send the board to others, etc. It seems obvious this is the case in retrospect, but I think it would be good to mention to make the gossip nature of this part of the protocol clear.
More importantly, I think there is a large issue with this push-only server communication. Imagine the following scenario:
- Bob publishes a new version of his board.
- Server A receives and stores this version.
- Alice can view Bob’s latest post using Server A, and all is well.
- Server A goes offline, perhaps for a day or two.
- Bob publishes a new version of his board. Server A never receives this update.
- Server A comes back online.
- Alice uses Server A, and thinks she is getting Bob’s latest post, but she is not.
Obviously it’s impossible to always have perfect consistency, and in the scenario described things would eventually work out, but I still think this is a problem. It is easily solved by speccing a server-to-server pull mechanism as well.
This could be something like:
On server start up and at every interval X, do a GET request for each key this server is aware of to two random servers in the realm.
X should be something long like several days.
This would require all servers to allow GET /<key> requests for anyone, which goes against a
later part of the spec:
Servers are not obligated to provide this endpoint for all requesters; they might provide it only to users of a particular client, or only to users who have paid for access, or according to any other scheme.
I get the idea behind this, and so I’m not sure how to reconcile it with what I’ve said above. I lean towards requiring all servers to be open to everyone. This has the advantage of making all clients server-agnostic as well, if they want to be.
Finally, I’m no gossip protocol expert, but it seems like it would be easy for servers to be missed when only 5 are getting selected at random. It would be nice for someone who knows the math for these things to be able to explain the probability of servers being left behind.
Difficulty factor
The difficulty factor stuff is definitely cool. But I’m not sure if increasing difficulty only once most boards are used up makes sense. Without a single point-of-truth like a blockchain, this can introduce data races, as others have pointed out. Additionally, due to TTLs board will be disappearing all the time, so there would need to be literally millions of active users for the difficulty to become meaningful.
What if this difficulty factor was baked in from the start? Preventing spam from the inception of the protocol/realm seems better than only near the end. For example the spec could define a difficulty based on a numerical threshold, or keys needing to have X preceding zeros, etc. Whatever works in a way that doesn’t weaken Ed25519 (!!). That number would be picked to have a meaningful difficulty for modern computers, taking maybe 10 minutes or more.
Client -> Server interaction
I understand this is a draft, but I just thought I’d mention that the spec doesn’t explain how clients are supposed to talk to servers, beyond the APIs available.
For example, when a client user updates their board, what servers does that client send the new board to? Just its favourite one? A random selection from the realm list? Etc.
One section of the spec alludes to clients maintaining lists of trusted servers, so I expect details on all this are coming. Looking forward to hearing them!
If the signature is not valid, the client must drop the response and remove the server from its list of trustworthy peers.
“The agony and ecstasy of public key cryptography”
I love this section. Cryptography is beautiful magic, and I’m glad to see it used and appreciated here.
Nitpicks
Here are some small comments or questions I have about the spec. They don’t change my feelings overall.
- Why is the limit 2217 bytes? I’m unable to find any meaning behind this number online. It seems to me that this should probably be larger, or at least well explained and justified.
- Limiting to HTTP/1.1 seems unecessary, allowing HTTP/2 to be used transparently by servers that support it would do no harm
- How do clients enforce the board aspect ratio? I don’t know enough about HTML/CSS to understand
how boards wouldn’t just be able to override this with
!importantor something. - The client is supposed to “open links in new windows or tabs” — how does that work when the board HTML might specifically say to open in the same tab?
- It would be nice to have the correct Content Security Policy in the spec, as they look tricky to get right.
- The protocol mentions TLS but doesn’t specifically disallow non-TLS servers. Would be good to see that spelled out.
- Putting the exact CORS requirements needed in the spec would be helpful, as CORS is tricky to get right.
- It’s not mentioned, but it seems like servers should reject PUT requests if the last-modified
meta tag is older or equal to the timestamp of the server’s version of the board, same is
If-Unmodified-Since - The
Preferheader in the spec looks like a big fancy official header likeVaryorAcceptand I was surprised to look it up and find out it’s not. I could see it becoming one in the future though, so it might be better to use something likeSpring-Prefer. - 2217 bytes * 10 million is indeed 22.17 GB, but it is also 20.65 GiB, and the latter is more meaningful for computers.
Odds and ends
Here are few thoughts that popped into my head while reading, I couldn’t fit them into other sections.
- Nothing mentions how often servers should update their realm list
- DNS could be used to get around having to share public keys with people
- Set a TXT record on
_spring83.mydomain.comwith your public key - Then clients will resolve that, so you can just tell your friends to follow you by entering
mydomain.com
- Set a TXT record on
Conclusion
I’m quite excited about this protocol, and will be following its development closely. As usual, I’d like to dive in over my head and start developing a client and server, but I will hold off this time, until the spec is a bit more finalized, and likely until Robin releases his software as well. I’ve got my hands full working on a secret DNS project for now anyway 😉. But I will definitely be participating when the time comes. Having a little space of HTML to share, with strict limits — it sounds like an awesome way to experiment and get creative. I look forward to it!