upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitor Pamplona <vitor@vitorpamplona.com>2024-04-24 15:31:45 -0400
committerGitHub <noreply@github.com>2024-04-24 16:31:45 -0300
commitdf30012430c88d49fb5b124992b04d5c61b6338b (patch)
treee24e45e6580e11aaade5d7ef79678a1af0a7eb6d
parentcab47cf0f179f578bf9d3be0e61a5a2224053f33 (diff)
NIP-17 (old 24) Sealed Gift-Wrapped Messages for Private DMs and Small Group Chats (#686)
-rw-r--r--04.md2
-rw-r--r--11.md2
-rw-r--r--17.md154
-rw-r--r--README.md9
4 files changed, 162 insertions, 5 deletions
diff --git a/04.md b/04.md
index dc232b4..a561a2f 100644
--- a/04.md
+++ b/04.md
@@ -1,4 +1,4 @@
1> __Warning__ `unrecommended`: deprecated in favor of [NIP-44](44.md) 1> __Warning__ `unrecommended`: deprecated in favor of [NIP-17](17.md)
2 2
3NIP-04 3NIP-04
4====== 4======
diff --git a/11.md b/11.md
index 45102d7..a50038a 100644
--- a/11.md
+++ b/11.md
@@ -37,7 +37,7 @@ Detailed plain-text information about the relay may be contained in the `descrip
37 37
38### Pubkey 38### Pubkey
39 39
40An administrative contact may be listed with a `pubkey`, in the same format as Nostr events (32-byte hex for a `secp256k1` public key). If a contact is listed, this provides clients with a recommended address to send encrypted direct messages (See `NIP-04`) to a system administrator. Expected uses of this address are to report abuse or illegal content, file bug reports, or request other technical assistance. 40An administrative contact may be listed with a `pubkey`, in the same format as Nostr events (32-byte hex for a `secp256k1` public key). If a contact is listed, this provides clients with a recommended address to send encrypted direct messages (See [NIP-17](17.md)) to a system administrator. Expected uses of this address are to report abuse or illegal content, file bug reports, or request other technical assistance.
41 41
42Relay operators have no obligation to respond to direct messages. 42Relay operators have no obligation to respond to direct messages.
43 43
diff --git a/17.md b/17.md
new file mode 100644
index 0000000..cc04a88
--- /dev/null
+++ b/17.md
@@ -0,0 +1,154 @@
1NIP-17
2======
3
4Private Direct Messages
5-----------------------
6
7`draft` `optional`
8
9This 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
13Kind `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
34Tags that mention, quote and assemble threading structures MUST follow [NIP-10](10.md).
35
36Kind `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
40The 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
42Clients SHOULD render messages of the same room in a continuous thread.
43
44An 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
48Following [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
75The encryption algorithm MUST use the latest version of [NIP-44](44.md).
76
77Clients 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
79Clients 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
81The 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
83Clients 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
87Kind `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
101Clients 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
103Clients 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
107This NIP offers the following privacy and security features:
108
1091. **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.
1102. **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.
1113. **No Moderation**: There are no group admins: no invitations or bans.
1124. **No Shared Secrets**: No secret must be known to all members that can leak or be mistakenly shared
1135. **Fully Recoverable**: Messages can be fully recoverable by any client with the user's private key
1146. **Optional Forward Secrecy**: Users and clients can opt-in for "disappearing messages".
1157. **Uses Public Relays**: Messages can flow through public relays without loss of privacy. Private relays can increase privacy further, but they are not required.
1168. **Cold Storage**: Users can unilaterally opt-in to sharing their messages with a separate key that is exclusive for DM backup and recovery.
117
118The 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
124This example sends the message `Hola, que tal?` from `nsec1w8udu59ydjvedgs3yv5qccshcj8k05fh3l60k9x57asjrqdpa00qkmr89m` to `nsec12ywtkplvyq5t6twdqwwygavp5lm4fhuang89c943nf2z92eez43szvn4dt`.
125
126The 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```
diff --git a/README.md b/README.md
index 5fcdaf7..619c984 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
25- [NIP-01: Basic protocol flow description](01.md) 25- [NIP-01: Basic protocol flow description](01.md)
26- [NIP-02: Follow List](02.md) 26- [NIP-02: Follow List](02.md)
27- [NIP-03: OpenTimestamps Attestations for Events](03.md) 27- [NIP-03: OpenTimestamps Attestations for Events](03.md)
28- [NIP-04: Encrypted Direct Message](04.md) --- **unrecommended**: deprecated in favor of [NIP-44](44.md) 28- [NIP-04: Encrypted Direct Message](04.md) --- **unrecommended**: deprecated in favor of [NIP-17](17.md)
29- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md) 29- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md)
30- [NIP-06: Basic key derivation from mnemonic seed phrase](06.md) 30- [NIP-06: Basic key derivation from mnemonic seed phrase](06.md)
31- [NIP-07: `window.nostr` capability for web browsers](07.md) 31- [NIP-07: `window.nostr` capability for web browsers](07.md)
@@ -36,6 +36,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
36- [NIP-13: Proof of Work](13.md) 36- [NIP-13: Proof of Work](13.md)
37- [NIP-14: Subject tag in text events](14.md) 37- [NIP-14: Subject tag in text events](14.md)
38- [NIP-15: Nostr Marketplace (for resilient marketplaces)](15.md) 38- [NIP-15: Nostr Marketplace (for resilient marketplaces)](15.md)
39- [NIP-17: Private Direct Messages](17.md)
39- [NIP-18: Reposts](18.md) 40- [NIP-18: Reposts](18.md)
40- [NIP-19: bech32-encoded entities](19.md) 41- [NIP-19: bech32-encoded entities](19.md)
41- [NIP-21: `nostr:` URI scheme](21.md) 42- [NIP-21: `nostr:` URI scheme](21.md)
@@ -99,6 +100,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
99| `11` | Group Thread | [29](29.md) | 100| `11` | Group Thread | [29](29.md) |
100| `12` | Group Thread Reply | [29](29.md) | 101| `12` | Group Thread Reply | [29](29.md) |
101| `13` | Seal | [59](59.md) | 102| `13` | Seal | [59](59.md) |
103| `14` | Direct Message | [17](17.md) |
102| `16` | Generic Repost | [18](18.md) | 104| `16` | Generic Repost | [18](18.md) |
103| `40` | Channel Creation | [28](28.md) | 105| `40` | Channel Creation | [28](28.md) |
104| `41` | Channel Metadata | [28](28.md) | 106| `41` | Channel Metadata | [28](28.md) |
@@ -138,6 +140,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
138| `10009` | User groups | [51](51.md), [29](29.md) | 140| `10009` | User groups | [51](51.md), [29](29.md) |
139| `10015` | Interests list | [51](51.md) | 141| `10015` | Interests list | [51](51.md) |
140| `10030` | User emoji list | [51](51.md) | 142| `10030` | User emoji list | [51](51.md) |
143| `10050` | Relay list to receive DMs | [17](17.md) |
141| `10096` | File storage server list | [96](96.md) | 144| `10096` | File storage server list | [96](96.md) |
142| `13194` | Wallet Info | [47](47.md) | 145| `13194` | Wallet Info | [47](47.md) |
143| `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] | 146| `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] |
@@ -247,10 +250,10 @@ Please update these lists when proposing NIPs introducing new event kinds.
247| `price` | price | currency, frequency | [99](99.md) | 250| `price` | price | currency, frequency | [99](99.md) |
248| `proxy` | external ID | protocol | [48](48.md) | 251| `proxy` | external ID | protocol | [48](48.md) |
249| `published_at` | unix timestamp (string) | -- | [23](23.md) | 252| `published_at` | unix timestamp (string) | -- | [23](23.md) |
250| `relay` | relay url | -- | [42](42.md) | 253| `relay` | relay url | -- | [42](42.md), [17](17.md) |
251| `relays` | relay list | -- | [57](57.md) | 254| `relays` | relay list | -- | [57](57.md) |
252| `server` | file storage server url | -- | [96](96.md) | 255| `server` | file storage server url | -- | [96](96.md) |
253| `subject` | subject | -- | [14](14.md) | 256| `subject` | subject | -- | [14](14.md), [17](17.md) |
254| `summary` | article summary | -- | [23](23.md) | 257| `summary` | article summary | -- | [23](23.md) |
255| `thumb` | badge thumbnail | dimensions in pixels | [58](58.md) | 258| `thumb` | badge thumbnail | dimensions in pixels | [58](58.md) |
256| `title` | article title | -- | [23](23.md) | 259| `title` | article title | -- | [23](23.md) |