-
@ Martti Malmi
2025-02-27 18:51:11NIP-118
Nostr Double Ratchet Invites
In order to start a NIP-117 Nostr Double Ratchet session, Alice and Bob need to exchange ephemeral public keys and a shared secret.
In a Nostr Double Ratchet invite, Alice gives Bob her
- ephemeral public key, which is also used to respond to the invite on Nostr,
- shared secret, and
- Nostr identity public key, which is used to authenticate the exchange.
Nostr event
Publishing an invite event on Nostr allows other users to start a Double Ratchet session with you.
typescript { pubkey: inviterIdentityKey, content: '', tags: [ ['d', `double-ratchet/invites/${uid}`], // uid: unique name for the invitation, e.g. "public" ['l', 'double-ratchet/invites'], // label, for listing all your invites ['ephemeralKey', inviterEphemeralKey], ['sharedSecret', sharedSecret] ], kind: 30078, created_at, id, sig }
l
is a NIP-32 label tag that can be used to list your invites. We use this approach with NIP-78 application specific data kind30078
in order to not bloat the event kind space and instead have a human-readable label.URL
Invites can be also shared privately, without requiring a Nostr event. This improves privacy, removing the public association between the inviter and response.
URL and QR code are often convenient ways to share privately, especially when the other user is not yet on Nostr. Format:
typescript const invite = { inviter, ephemeralKey, sharedSecret }; const json = JSON.stringify(invite); const url = `https://example.com/#${encodeURIComponent(json)}`;
Encoding the invite into the URL hash ensures it's not sent to the server and logged by default.
nostr:
URI scheme is another possible way to share invites, when we have native clients supporting the feature.Invite response
Outer event
Invite response outer event is a NIP-59 gift wrap event of kind
1059
, sent from a random, one-time-use pubkey, hiding the responder's identity from the public.It is addressed to the ephemeral key in the invite. If the invite was publicly shared, responses can be publicly associated to the inviter.
Inner event
NIP-59 Rumor.
```typescript const conversationKey = nip44.getConversationKey( inviteeKeyPair, inviterPublicKey ); const encrypted1 = encrypt(inviteeEphemeralKey, conversationKey); const encrypted2 = encrypt(encrypted1, sharedSecret);
const rumor = { pubkey: inviteePublicKey, kind: 1060, content: encrypted2, tags: [], createdAt, id, }; ```
After receiving the invite response, both parties have what they need to start a double ratchet session: each others' ephemeral public keys and a shared secret.
Both parties have authenticated by encrypting or decrypting using their nip44 conversation key.
The shared secret from the invite is used in the response to ensure that only actual recipients of the invite can follow it. Otherwise, attackers could initiate double ratchet sessions by sending invite responses to all addresses that received gift wraps, some of which are private invite addresses.