|
| 1 | +NIP-17 |
| 2 | +====== |
| 3 | + |
| 4 | +Private Direct Messages |
| 5 | +----------------------- |
| 6 | + |
| 7 | +`draft` `optional` |
| 8 | + |
| 9 | +This NIP defines an encrypted direct messaging scheme using [NIP-44](44.md) encryption and [NIP-59](59.md) seals and gift wraps. |
| 10 | + |
| 11 | +## Direct Message Kind |
| 12 | + |
| 13 | +Kind `14` is a chat message. `p` tags identify one or more receivers of the message. |
| 14 | + |
| 15 | +```js |
| 16 | +{ |
| 17 | + "id": "<usual hash>", |
| 18 | + "pubkey": "<sender-pubkey>", |
| 19 | + "created_at": now(), |
| 20 | + "kind": 14, |
| 21 | + "tags": [ |
| 22 | + ["p", "<receiver-1-pubkey>", "<relay-url>"], |
| 23 | + ["p", "<receiver-2-pubkey>", "<relay-url>"], |
| 24 | + ["e", "<kind-14-id>", "<relay-url>", "reply"] // if this is a reply |
| 25 | + ["subject", "<conversation-title>"], |
| 26 | + ... |
| 27 | + ], |
| 28 | + "content": "<message-in-plain-text>", |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +`.content` MUST be plain text. Fields `id` and `created_at` are required. |
| 33 | + |
| 34 | +Tags that mention, quote and assemble threading structures MUST follow [NIP-10](10.md). |
| 35 | + |
| 36 | +Kind `14`s MUST never be signed. If it is signed, the message might leak to relays and become **fully public**. |
| 37 | + |
| 38 | +## Chat Rooms |
| 39 | + |
| 40 | +The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or a current one is removed, a new room is created with clean message history. |
| 41 | + |
| 42 | +Clients SHOULD render messages of the same room in a continuous thread. |
| 43 | + |
| 44 | +An optional `subject` tag defines the current name/topic of the conversation. Any member can change the topic by simply submitting a new `subject` to an existing `pubkey` + `p`-tags room. There is no need to send `subject` in every message. The newest `subject` in the thread is the subject of the conversation. |
| 45 | + |
| 46 | +## Encrypting |
| 47 | + |
| 48 | +Following [NIP-59](59.md), the **unsigned** `kind:14` chat message must be sealed (`kind:13`) and then gift-wrapped (`kind:1059`) to each receiver and the sender individually. |
| 49 | + |
| 50 | +```js |
| 51 | +{ |
| 52 | + "id": "<usual hash>", |
| 53 | + "pubkey": randomPublicKey, |
| 54 | + "created_at": randomTimeUpTo2DaysInThePast(), |
| 55 | + "kind": 1059, // gift wrap |
| 56 | + "tags": [ |
| 57 | + ["p", receiverPublicKey, "<relay-url>"] // receiver |
| 58 | + ], |
| 59 | + "content": nip44Encrypt( |
| 60 | + { |
| 61 | + "id": "<usual hash>", |
| 62 | + "pubkey": senderPublicKey, |
| 63 | + "created_at": randomTimeUpTo2DaysInThePast(), |
| 64 | + "kind": 13, // seal |
| 65 | + "tags": [], // no tags |
| 66 | + "content": nip44Encrypt(unsignedKind14, senderPrivateKey, receiverPublicKey), |
| 67 | + "sig": "<signed by senderPrivateKey>" |
| 68 | + }, |
| 69 | + randomPrivateKey, receiverPublicKey |
| 70 | + ), |
| 71 | + "sig": "<signed by randomPrivateKey>" |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +The encryption algorithm MUST use the latest version of [NIP-44](44.md). |
| 76 | + |
| 77 | +Clients MUST verify if pubkey of the `kind:13` is the same pubkey on the `kind:14`, otherwise any sender can impersonate others by simply changing the pubkey on `kind:14`. |
| 78 | + |
| 79 | +Clients SHOULD randomize `created_at` in up to two days in the past in both the seal and the gift wrap to make sure grouping by `created_at` doesn't reveal any metadata. |
| 80 | + |
| 81 | +The gift wrap's `p`-tag can be the receiver's main pubkey or an alias key created to receive DMs without exposing the receiver's identity. |
| 82 | + |
| 83 | +Clients CAN offer disappearing messages by setting an `expiration` tag in the gift wrap of each receiver or by not generating a gift wrap to the sender's public key |
| 84 | + |
| 85 | +## Publishing |
| 86 | + |
| 87 | +Kind `10050` indicates the user's preferred relays to receive DMs. The event MUST include a list of `relay` tags with relay URIs. |
| 88 | + |
| 89 | +```js |
| 90 | +{ |
| 91 | + "kind": 10050, |
| 92 | + "tags": [ |
| 93 | + ["relay", "wss://inbox.nostr.wine"], |
| 94 | + ["relay", "wss://myrelay.nostr1.com"], |
| 95 | + ], |
| 96 | + "content": "", |
| 97 | + //...other fields |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +Clients SHOULD publish kind `14` events to the `10050`-listed relays, falling back to `read` relays of [NIP-65](65.md) if `kind:10050` is not available. |
| 102 | + |
| 103 | +Clients SHOULD guide users to keep `kind:10050` lists small (1-3 relays) and SHOULD spread it to as many relays as viable. |
| 104 | + |
| 105 | +## Benefits & Limitations |
| 106 | + |
| 107 | +This NIP offers the following privacy and security features: |
| 108 | + |
| 109 | +1. **No Metadata Leak**: Participant identities, each message's real date and time, event kinds, and other event tags are all hidden from the public. Senders and receivers cannot be linked with public information alone. |
| 110 | +2. **No Public Group Identifiers**: There is no public central queue, channel or otherwise converging identifier to correlate or count all messages in the same group. |
| 111 | +3. **No Moderation**: There are no group admins: no invitations or bans. |
| 112 | +4. **No Shared Secrets**: No secret must be known to all members that can leak or be mistakenly shared |
| 113 | +5. **Fully Recoverable**: Messages can be fully recoverable by any client with the user's private key |
| 114 | +6. **Optional Forward Secrecy**: Users and clients can opt-in for "disappearing messages". |
| 115 | +7. **Uses Public Relays**: Messages can flow through public relays without loss of privacy. Private relays can increase privacy further, but they are not required. |
| 116 | +8. **Cold Storage**: Users can unilaterally opt-in to sharing their messages with a separate key that is exclusive for DM backup and recovery. |
| 117 | + |
| 118 | +The main limitation of this approach is having to send a separate encrypted event to each receiver. Group chats with more than 100 participants should find a more suitable messaging scheme. |
| 119 | + |
| 120 | +---- |
| 121 | + |
| 122 | +## Examples |
| 123 | + |
| 124 | +This example sends the message `Hola, que tal?` from `nsec1w8udu59ydjvedgs3yv5qccshcj8k05fh3l60k9x57asjrqdpa00qkmr89m` to `nsec12ywtkplvyq5t6twdqwwygavp5lm4fhuang89c943nf2z92eez43szvn4dt`. |
| 125 | + |
| 126 | +The two final GiftWraps, one to the receiver and the other to the sender, are: |
| 127 | + |
| 128 | +```json |
| 129 | +{ |
| 130 | + "id":"2886780f7349afc1344047524540ee716f7bdc1b64191699855662330bf235d8", |
| 131 | + "pubkey":"8f8a7ec43b77d25799281207e1a47f7a654755055788f7482653f9c9661c6d51", |
| 132 | + "created_at":1703128320, |
| 133 | + "kind":1059, |
| 134 | + "tags":[ |
| 135 | + [ "p", "918e2da906df4ccd12c8ac672d8335add131a4cf9d27ce42b3bb3625755f0788"] |
| 136 | + ], |
| 137 | + "content":"AsqzdlMsG304G8h08bE67dhAR1gFTzTckUUyuvndZ8LrGCvwI4pgC3d6hyAK0Wo9gtkLqSr2rT2RyHlE5wRqbCOlQ8WvJEKwqwIJwT5PO3l2RxvGCHDbd1b1o40ZgIVwwLCfOWJ86I5upXe8K5AgpxYTOM1BD+SbgI5jOMA8tgpRoitJedVSvBZsmwAxXM7o7sbOON4MXHzOqOZpALpS2zgBDXSAaYAsTdEM4qqFeik+zTk3+L6NYuftGidqVluicwSGS2viYWr5OiJ1zrj1ERhYSGLpQnPKrqDaDi7R1KrHGFGyLgkJveY/45y0rv9aVIw9IWF11u53cf2CP7akACel2WvZdl1htEwFu/v9cFXD06fNVZjfx3OssKM/uHPE9XvZttQboAvP5UoK6lv9o3d+0GM4/3zP+yO3C0NExz1ZgFmbGFz703YJzM+zpKCOXaZyzPjADXp8qBBeVc5lmJqiCL4solZpxA1865yPigPAZcc9acSUlg23J1dptFK4n3Tl5HfSHP+oZ/QS/SHWbVFCtq7ZMQSRxLgEitfglTNz9P1CnpMwmW/Y4Gm5zdkv0JrdUVrn2UO9ARdHlPsW5ARgDmzaxnJypkfoHXNfxGGXWRk0sKLbz/ipnaQP/eFJv/ibNuSfqL6E4BnN/tHJSHYEaTQ/PdrA2i9laG3vJti3kAl5Ih87ct0w/tzYfp4SRPhEF1zzue9G/16eJEMzwmhQ5Ec7jJVcVGa4RltqnuF8unUu3iSRTQ+/MNNUkK6Mk+YuaJJs6Fjw6tRHuWi57SdKKv7GGkr0zlBUU2Dyo1MwpAqzsCcCTeQSv+8qt4wLf4uhU9Br7F/L0ZY9bFgh6iLDCdB+4iABXyZwT7Ufn762195hrSHcU4Okt0Zns9EeiBOFxnmpXEslYkYBpXw70GmymQfJlFOfoEp93QKCMS2DAEVeI51dJV1e+6t3pCSsQN69Vg6jUCsm1TMxSs2VX4BRbq562+VffchvW2BB4gMjsvHVUSRl8i5/ZSDlfzSPXcSGALLHBRzy+gn0oXXJ/447VHYZJDL3Ig8+QW5oFMgnWYhuwI5QSLEyflUrfSz+Pdwn/5eyjybXKJftePBD9Q+8NQ8zulU5sqvsMeIx/bBUx0fmOXsS3vjqCXW5IjkmSUV7q54GewZqTQBlcx+90xh/LSUxXex7UwZwRnifvyCbZ+zwNTHNb12chYeNjMV7kAIr3cGQv8vlOMM8ajyaZ5KVy7HpSXQjz4PGT2/nXbL5jKt8Lx0erGXsSsazkdoYDG3U", |
| 138 | + "sig":"a3c6ce632b145c0869423c1afaff4a6d764a9b64dedaf15f170b944ead67227518a72e455567ca1c2a0d187832cecbde7ed478395ec4c95dd3e71749ed66c480" |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +```json |
| 143 | +{ |
| 144 | + "id":"162b0611a1911cfcb30f8a5502792b346e535a45658b3a31ae5c178465509721", |
| 145 | + "pubkey":"626be2af274b29ea4816ad672ee452b7cf96bbb4836815a55699ae402183f512", |
| 146 | + "created_at":1702711587, |
| 147 | + "kind":1059, |
| 148 | + "tags":[ |
| 149 | + [ "p", "44900586091b284416a0c001f677f9c49f7639a55c3f1e2ec130a8e1a7998e1b"] |
| 150 | + ], |
| 151 | + "content":"AsTClTzr0gzXXji7uye5UB6LYrx3HDjWGdkNaBS6BAX9CpHa+Vvtt5oI2xJrmWLen+Fo2NBOFazvl285Gb3HSM82gVycrzx1HUAaQDUG6HI7XBEGqBhQMUNwNMiN2dnilBMFC3Yc8ehCJT/gkbiNKOpwd2rFibMFRMDKai2mq2lBtPJF18oszKOjA+XlOJV8JRbmcAanTbEK5nA/GnG3eGUiUzhiYBoHomj3vztYYxc0QYHOx0WxiHY8dsC6jPsXC7f6k4P+Hv5ZiyTfzvjkSJOckel1lZuE5SfeZ0nduqTlxREGeBJ8amOykgEIKdH2VZBZB+qtOMc7ez9dz4wffGwBDA7912NFS2dPBr6txHNxBUkDZKFbuD5wijvonZDvfWq43tZspO4NutSokZB99uEiRH8NAUdGTiNb25m9JcDhVfdmABqTg5fIwwTwlem5aXIy8b66lmqqz2LBzJtnJDu36bDwkILph3kmvaKPD8qJXmPQ4yGpxIbYSTCohgt2/I0TKJNmqNvSN+IVoUuC7ZOfUV9lOV8Ri0AMfSr2YsdZ9ofV5o82ClZWlWiSWZwy6ypa7CuT1PEGHzywB4CZ5ucpO60Z7hnBQxHLiAQIO/QhiBp1rmrdQZFN6PUEjFDloykoeHe345Yqy9Ke95HIKUCS9yJurD+nZjjgOxZjoFCsB1hQAwINTIS3FbYOibZnQwv8PXvcSOqVZxC9U0+WuagK7IwxzhGZY3vLRrX01oujiRrevB4xbW7Oxi/Agp7CQGlJXCgmRE8Rhm+Vj2s+wc/4VLNZRHDcwtfejogjrjdi8p6nfUyqoQRRPARzRGUnnCbh+LqhigT6gQf3sVilnydMRScEc0/YYNLWnaw9nbyBa7wFBAiGbJwO40k39wj+xT6HTSbSUgFZzopxroO3f/o4+ubx2+IL3fkev22mEN38+dFmYF3zE+hpE7jVxrJpC3EP9PLoFgFPKCuctMnjXmeHoiGs756N5r1Mm1ffZu4H19MSuALJlxQR7VXE/LzxRXDuaB2u9days/6muP6gbGX1ASxbJd/ou8+viHmSC/ioHzNjItVCPaJjDyc6bv+gs1NPCt0qZ69G+JmgHW/PsMMeL4n5bh74g0fJSHqiI9ewEmOG/8bedSREv2XXtKV39STxPweceIOh0k23s3N6+wvuSUAJE7u1LkDo14cobtZ/MCw/QhimYPd1u5HnEJvRhPxz0nVPz0QqL/YQeOkAYk7uzgeb2yPzJ6DBtnTnGDkglekhVzQBFRJdk740LEj6swkJ", |
| 152 | + "sig":"c94e74533b482aa8eeeb54ae72a5303e0b21f62909ca43c8ef06b0357412d6f8a92f96e1a205102753777fd25321a58fba3fb384eee114bd53ce6c06a1c22bab" |
| 153 | +} |
| 154 | +``` |
0 commit comments