Will Keychat, 0xchat and White Noise all be able to interoperate? I can't quite picture how the UX would work if I create a group in Keychat and then somehow who uses 0xchat or White Noise wants to join.
Discussion
Interoperability between the three clients in an MLS group isn’t hard, since they’re all built on OpenMLS and use shared relays.
The main difference is that Keychat uses a different “envelope” format for MLS messages compared to the other two clients. We need to write a note explaining the design rationale behind this “envelope” format, and we truly hope to have 0xChat’s understanding and support.
Is there any specification available regarding this envelope format?
We've been using the metaphor of a letter: the envelope is where the sending and receiving addresses are written. To protect metadata privacy, both the sending and receiving addresses need to be updated frequently.
NIP-EE group events
{
"id":
"kind": 445,
"created_at":
"pubkey":
"content":
"tags": [
["h",
],
"sig":
}
In the NIP-EE group event, the content field is first encrypted using MLS, and then encrypted again using NIP-44. The NIP-44 encryption is done using a Nostr keypair generated from the MLS exporter_secret to calculate the conversation key value. Keychat follows the same approach. The public key—used as the sender address—is randomly generated, and Keychat does this as well.
The difference lies in the receiving address. In NIP-EE, the receiving address is set using:
"tags": [ ["h",
The h tag represents the Nostr group ID (from the Nostr Group Data Extension). Updating the group ID requires a member to send a commit message.
Keychat, on the other hand, uses:
"tags": [ ["p",
This receiverPublicKey is derived from the MLS exporter_secret, so it updates automatically without the need for a separate commit message.
Keychat uses kind: 1059, as it satisfies the constraints of kind 1059, enabling the integration of both MLS messages and NIP-17 DMs in a unified format.
Thanks for the information! From what I understand, the Nostr group ID probably doesn't need to change—but please correct me if I'm wrong. That said, I do think using a pubkey derived from the exporter_secret as the receiver is a good idea.
Using different kind values for MLS messages might be better than sharing kind 1059, since they serve different purposes—especially when it comes to filtering MLS messages specifically.
If there are differing opinions, perhaps it would be a good idea to propose a new NIP or extend NIP-EE. That way, different clients can work together to choose a solution that fits best for everyone.
Really glad you like the idea of deriving the receiving address from the exporter_secret.
If the Nostr group ID doesn't change, external observers can see how frequently and at what times the group communicates, even though the ID itself is anonymous. If I remember correctly, NIP-EE just hasn't specified how to update this ID yet, but it plans to in the future.
A gift wrap event is a kind:1059 event that wraps any other event. It's a general-purpose gift wrap — the inner event can be of any kind. Think about NIP-17 DMs: external observers can only see that it's a kind:1059 event.
And how about the keypackages?
Keychat's current MLS KeyPackage event is a replaceable event, which makes it easier to update and manage the KeyPackage. Events are replaceable, which means that for each combination of pubkey and kind, only the latest event must be stored by relays, and older versions may be discarded.
In addition, after a new member joins a group, an update commit is performed immediately.
Keychat can also publish the KeyPackage using NIP-EE’s kind: 443.
What do you think about using replaceable events to update and manage KeyPackages?
Yes, I agree that using replaceable events helps reduce the need for manual deletion and management—I’ve considered this before as well.
And I think we could even use addressable events, with the d tag to indicate different clients and devices, so that each device or client can maintain its own KeyPackage.
This is cool!
Thanks for explaining 🙏. Great thread here.
Yeah, this UX would definitely be a challenge.
Keychat probably doesn't follow the NIP-EE, but I think it's something worth considering. nostr:npub1h0uj825jgcr9lzxyp37ehasuenq070707pj63je07n8mkcsg3u0qnsrwx8
At first glance it looks to me like you follow NIP-EE in order to interop then you have to follow that NIP super carefully. So many checklist items in there that you cannot not tick.
When creating a brand-new application-layer spec, is it better for one team to define the spec first and have others build apps around it? Or should multiple teams start by building apps independently and then work together to converge on the best possible spec?
One thing a lot of specs could benefit from is ecash stamps.
We strongly recommend reading the MLS specification directly, rather than relying solely on NIP-EE.
I read this MIMI doc, traumatic flashbacks to Feynman diagrams in old textbooks.
https://www.ietf.org/archive/id/draft-ietf-mimi-protocol-01.html
I don't quite get your point. NIP-EE also follows the MLS specification, it just standardizes the use of Nostr events to send mls messages.