diff options
| author | Alex Gleason <alex@alexgleason.me> | 2026-04-10 13:31:37 -0500 |
|---|---|---|
| committer | Alex Gleason <alex@alexgleason.me> | 2026-04-10 13:31:37 -0500 |
| commit | 5e1e24766910fc07cb61a049aed2623987458ec2 (patch) | |
| tree | b7588f61fddf9374268d5cd6f4e3f2655d7c840a /59.md | |
| parent | b8782df594b4e7e8f088869134908eed58be6078 (diff) | |
| parent | 3465f540e3eaedccb5309711b502f0febf56b52f (diff) | |
Merge nip44-big-payloads into bigger-nip44bigger-nip44
Diffstat (limited to '59.md')
| -rw-r--r-- | 59.md | 35 |
1 files changed, 20 insertions, 15 deletions
| @@ -4,7 +4,7 @@ NIP-59 | |||
| 4 | Gift Wrap | 4 | Gift Wrap |
| 5 | --------- | 5 | --------- |
| 6 | 6 | ||
| 7 | `optional` | 7 | `optional` `relay` |
| 8 | 8 | ||
| 9 | This NIP defines a protocol for encapsulating any nostr event. This makes it possible to obscure most metadata | 9 | This NIP defines a protocol for encapsulating any nostr event. This makes it possible to obscure most metadata |
| 10 | for a given event, perform collaborative signing, and more. | 10 | for a given event, perform collaborative signing, and more. |
| @@ -13,7 +13,7 @@ This NIP *does not* define any messaging protocol. Applications of this NIP shou | |||
| 13 | 13 | ||
| 14 | This NIP relies on [NIP-44](./44.md)'s versioned encryption algorithms. | 14 | This NIP relies on [NIP-44](./44.md)'s versioned encryption algorithms. |
| 15 | 15 | ||
| 16 | # Overview | 16 | ## Overview |
| 17 | 17 | ||
| 18 | This protocol uses three main concepts to protect the transmission of a target event: `rumor`s, `seal`s, and `gift wrap`s. | 18 | This protocol uses three main concepts to protect the transmission of a target event: `rumor`s, `seal`s, and `gift wrap`s. |
| 19 | 19 | ||
| @@ -29,13 +29,13 @@ This allows the isolation of concerns across layers: | |||
| 29 | - A seal identifies the author without revealing the content or the recipient. | 29 | - A seal identifies the author without revealing the content or the recipient. |
| 30 | - A gift wrap can add metadata (recipient, tags, a different author) without revealing the true author. | 30 | - A gift wrap can add metadata (recipient, tags, a different author) without revealing the true author. |
| 31 | 31 | ||
| 32 | # Protocol Description | 32 | ## Protocol Description |
| 33 | 33 | ||
| 34 | ## 1. The Rumor Event Kind | 34 | ### 1. The Rumor Event Kind |
| 35 | 35 | ||
| 36 | A `rumor` is the same thing as an unsigned event. Any event kind can be made a `rumor` by removing the signature. | 36 | A `rumor` is the same thing as an unsigned event. Any event kind can be made a `rumor` by removing the signature. |
| 37 | 37 | ||
| 38 | ## 2. The Seal Event Kind | 38 | ### 2. The Seal Event Kind |
| 39 | 39 | ||
| 40 | A `seal` is a `kind:13` event that wraps a `rumor` with the sender's regular key. The `seal` is **always** encrypted | 40 | A `seal` is a `kind:13` event that wraps a `rumor` with the sender's regular key. The `seal` is **always** encrypted |
| 41 | to a receiver's pubkey but there is no `p` tag pointing to the receiver. There is no way to know who the rumor is for | 41 | to a receiver's pubkey but there is no `p` tag pointing to the receiver. There is no way to know who the rumor is for |
| @@ -55,7 +55,7 @@ without the receiver's or the sender's private key. The only public information | |||
| 55 | 55 | ||
| 56 | Tags MUST always be empty in a `kind:13`. The inner event MUST always be unsigned. | 56 | Tags MUST always be empty in a `kind:13`. The inner event MUST always be unsigned. |
| 57 | 57 | ||
| 58 | ## 3. Gift Wrap Event Kind | 58 | ### 3. Gift Wrap Event Kind |
| 59 | 59 | ||
| 60 | A `gift wrap` event is a `kind:1059` event that wraps any other event. `tags` SHOULD include any information | 60 | A `gift wrap` event is a `kind:1059` event that wraps any other event. `tags` SHOULD include any information |
| 61 | needed to route the event to its intended recipient, including the recipient's `p` tag or [NIP-13](13.md) proof of work. | 61 | needed to route the event to its intended recipient, including the recipient's `p` tag or [NIP-13](13.md) proof of work. |
| @@ -72,12 +72,12 @@ needed to route the event to its intended recipient, including the recipient's ` | |||
| 72 | } | 72 | } |
| 73 | ``` | 73 | ``` |
| 74 | 74 | ||
| 75 | # Encrypting Payloads | 75 | ## Encrypting Payloads |
| 76 | 76 | ||
| 77 | Encryption is done following [NIP-44](44.md) on the JSON-encoded event. Place the encryption payload in the `.content` | 77 | Encryption is done following [NIP-44](44.md) on the JSON-encoded event. Place the encryption payload in the `.content` |
| 78 | of the wrapper event (either a `seal` or a `gift wrap`). | 78 | of the wrapper event (either a `seal` or a `gift wrap`). |
| 79 | 79 | ||
| 80 | # Other Considerations | 80 | ## Other Considerations |
| 81 | 81 | ||
| 82 | If a `rumor` is intended for more than one party, or if the author wants to retain an encrypted copy, a single | 82 | If a `rumor` is intended for more than one party, or if the author wants to retain an encrypted copy, a single |
| 83 | `rumor` may be wrapped and addressed for each recipient individually. | 83 | `rumor` may be wrapped and addressed for each recipient individually. |
| @@ -97,7 +97,12 @@ To protect recipient metadata, relays SHOULD only serve `kind 1059` events inten | |||
| 97 | When possible, clients should only send wrapped events to `read` relays for the recipient that implement | 97 | When possible, clients should only send wrapped events to `read` relays for the recipient that implement |
| 98 | AUTH, and refuse to serve wrapped events to non-recipients. | 98 | AUTH, and refuse to serve wrapped events to non-recipients. |
| 99 | 99 | ||
| 100 | # An Example | 100 | When adding expiration tags to both `seal` and `gift wrap` layers, implementations SHOULD use independent random timestamps for each layer. Using different `created_at` values increases timing variance and helps protect against metadata correlation attacks. |
| 101 | |||
| 102 | Since signing keys are random, relays SHOULD delete `kind 1059` events whose p-tag matches the signer of | ||
| 103 | [NIP-09](09.md) deletions or [NIP-62](62.md) vanish requests. | ||
| 104 | |||
| 105 | ## An Example | ||
| 101 | 106 | ||
| 102 | Let's send a wrapped `kind 1` message between two parties asking "Are you going to the party tonight?" | 107 | Let's send a wrapped `kind 1` message between two parties asking "Are you going to the party tonight?" |
| 103 | 108 | ||
| @@ -108,7 +113,7 @@ Let's send a wrapped `kind 1` message between two parties asking "Are you going | |||
| 108 | Note that this messaging protocol should not be used in practice, this is just an example. Refer to other | 113 | Note that this messaging protocol should not be used in practice, this is just an example. Refer to other |
| 109 | NIPs for concrete messaging protocols that depend on gift wraps. | 114 | NIPs for concrete messaging protocols that depend on gift wraps. |
| 110 | 115 | ||
| 111 | ## 1. Create an event | 116 | ### 1. Create an event |
| 112 | 117 | ||
| 113 | Create a `kind 1` event with the message, the receivers, and any other tags you want, signed by the author. | 118 | Create a `kind 1` event with the message, the receivers, and any other tags you want, signed by the author. |
| 114 | Do not sign the event. | 119 | Do not sign the event. |
| @@ -124,7 +129,7 @@ Do not sign the event. | |||
| 124 | } | 129 | } |
| 125 | ``` | 130 | ``` |
| 126 | 131 | ||
| 127 | ## 2. Seal the rumor | 132 | ### 2. Seal the rumor |
| 128 | 133 | ||
| 129 | Encrypt the JSON-encoded `rumor` with a conversation key derived using the author's private key and | 134 | Encrypt the JSON-encoded `rumor` with a conversation key derived using the author's private key and |
| 130 | the recipient's public key. Place the result in the `content` field of a `kind 13` `seal` event. Sign | 135 | the recipient's public key. Place the result in the `content` field of a `kind 13` `seal` event. Sign |
| @@ -142,7 +147,7 @@ it with the author's key. | |||
| 142 | } | 147 | } |
| 143 | ``` | 148 | ``` |
| 144 | 149 | ||
| 145 | ## 3. Wrap the seal | 150 | ### 3. Wrap the seal |
| 146 | 151 | ||
| 147 | Encrypt the JSON-encoded `kind 13` event with your ephemeral, single-use random key. Place the result | 152 | Encrypt the JSON-encoded `kind 13` event with your ephemeral, single-use random key. Place the result |
| 148 | in the `content` field of a `kind 1059`. Add a single `p` tag containing the recipient's public key. | 153 | in the `content` field of a `kind 1059`. Add a single `p` tag containing the recipient's public key. |
| @@ -160,13 +165,13 @@ Sign the `gift wrap` using the random key generated in the previous step. | |||
| 160 | } | 165 | } |
| 161 | ``` | 166 | ``` |
| 162 | 167 | ||
| 163 | ## 4. Broadcast Selectively | 168 | ### 4. Broadcast Selectively |
| 164 | 169 | ||
| 165 | Broadcast the `kind 1059` event to the recipient's relays only. Delete all the other events. | 170 | Broadcast the `kind 1059` event to the recipient's relays only. Delete all the other events. |
| 166 | 171 | ||
| 167 | # Code Samples | 172 | ## Code Samples |
| 168 | 173 | ||
| 169 | ## JavaScript | 174 | ### JavaScript |
| 170 | 175 | ||
| 171 | ```javascript | 176 | ```javascript |
| 172 | import {bytesToHex} from "@noble/hashes/utils" | 177 | import {bytesToHex} from "@noble/hashes/utils" |