This is the first in a series of weekly updates I’m publishing on my process around secure messaging. Since it’s the first, let’s start with a bit of historical context.
How this started
On April 29th I published a PR on the NIPs repo detailing how we could achieve “Double Ratchet” DMs on Nostr. There was also a video and demo app that went along with the PR. The basic premise was to use an adapted version of the Signal protocol. This would result in DMs that were truly private and confidential, even in the case where you leaked your main private key (your nsec).
I got a lot of great feedback from folks on that PR. Interestingly, nearly all of it focused on two points, both of which I’d deliberately scoped out. Group messaging and multi-device/client support. While I knew these were important, and I’d figured out how these might be accomplished, I’d scoped them out to try and keep the footprint of the spec as small as possible But, the more I talked to people, the more it became clear that this was one problem to be solved and given the complexity, it’d be better to do it in one shot.
At the same time, I’d seen that Messaging Layer Security (MLS) had recently made a lot of progress on becoming an internet standard with their RFC proposal and, goaded on by Vitor, decided to take a closer look.
Enter MLS
Messaging Layer Security (MLS) is a new protocal that is basically a modern extension of the Signal protocol that makes group messaging way more efficient (log vs linear) and was built to be used in centralized or federated environments. I’d heard other Nostr devs talk about it in the past but it was always overlooked as being too complicated or too early.
After spending a couple weeks reading hundreds of pages of RFC docs and reading through a few implementations of the MLS spec, I believe it’s the best solution for secure direct and group messaging in Nostr. It also has the added benefit that we can upgrade the underlying crypto primitives over time in a sane way.
The MLS protocol specifies “a key establishment protocol that provides efficient asynchronous group key establishment with forward secrecy (FS) and post-compromise security (PCS) for groups in size ranging from two to thousands.”
The spec I’m working on will detail the ways that we implement this protocol into the Nostr environment (namely, how do we use our crypto primitives, use events as control mechanisms, and use relays for storage, while obfuscating metadata).
Goals
It’s important to be clear about what we’re aiming for here. Engineering is all about tradeoffs, always.
- Private and Confidential DMs and Group messages
- Private means that an observer cannot tell that Alice and Bob are talking to one another, or that Alice is part of a specific group. This necessarily requires protecting metadata.
- Confidential means that the contents of conversations can only be viewed by the intended recipients.
- Forward secrecy and Post-compromise security (PCS) in the case of any key material being leaked, whether that’s your main Nostr identity key (your nsec) or any of the keys used in the MLS ratchet trees.
- Forward secrecy means that encrypted content in the past remains encrypted even if key material is leaked.
- Post compromise security means that leaking key material doesn’t allow an attacker to continue to read messages indefinitely into the future.
- Scales well for large groups. MLS provides this from a computational standpoint, but we need to make sure this works in a scalable way when multiple relays are involved.
- Allows for the use of multiple device/clients in a single conversation/group. Importantly, we’re not aiming to enable a device/client to be able to reconstruct the full history of a conversation at any point.
Progress this week
Ok, finally, what what I been up to?
Reading
I’ve spent most of the last few weeks reading the MLS spec and architectural doc (multiple times), learning some Rust, and beefing up my knowledge of cryptography (which was, if I’m being generous, paltry before starting this project).
Ciphersuites
Nostr is built around the same crypto primitives that Bitcoin is, namely Schnorr signatures over the secp256k1 curve and SHA-256 hashes. This curve isn’t currently supported officially in the MLS spec. I’ve been in touch with the MLS working group to better understand the process of adding a new ciphersuite to the set of ciphersuites in the MLS spec. The outcome here is that we’re going to start out using our custom ciphersuite that isn’t part of the formal spec. The only drawback being that Nostr’s MLS implementation won’t be immediately interoperable with other MLS implementations. We can always add it later via the formal channels if we want.
MLS Implementations
Given the complexity of the MLS spec itself (the RFC is 132 pages long), having a well vetted, well tested implementation is going to be key to adoption in the Nostr ecosystem. OpenMLS is an implementation created by several of the RFC authors and written in Rust with bindings for nearly all the major languages we would want to support.
I’ve been in touch with the maintainers to talk about adding support to their library for our new ciphersuite and to better understand the bindings that are there. Some (WASM) are very barebones and still need a lot of work. They are generally open to the idea of working with me on adding the missing pieces we’d need.
Double Ratchet NIP 2.0
I’ve also started to write up the new version of the NIP that will detail how all of this will work when plugged into Nostr. It’s not yet ready to share but it’s getting closer.
Onward & Upward
Hopefully that’s a helpful recap. I’ll keep doing these weekly and welcome any questions, feedback, or support. In particular, if you’re keen on working on this with me, please reach out. More eyes and more brains can only make this better. 🤙