clone

every nostr nip as a chapter of an illustrated, early-2000s printed game manual

main
nip.guide / site / nips / 59.html
59.html 28.6K
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-59 - Gift Wrap — Nostr Instruction Manual</title>7<meta name="description" content="NIP-59: gift wrap. Rumors, seals, and gift wraps hide event metadata behind two layers of NIP-44 encryption. Complete manual page.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter 59 - Encryption</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="59">59</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 59</div>50 <h1>Gift Wrap</h1>51 <p class="sub">Hide any event inside two layers of encryption, so relays see a package but never the sender, the content, or the conversation.</p>52 </div>53 </div>5455 <main class="spread">56 <div class="main">5758 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>59 <p>A normal Nostr event leaks metadata. Anyone can read the author, the timestamp, the kind, and the tags. This NIP defines a way to encapsulate any event so that most of this metadata is hidden. It also enables collaborative signing and other patterns.</p>60 <p>The protocol stacks three concepts: the <strong>rumor</strong>, the <strong>seal</strong>, and the <strong>gift wrap</strong>. A rumor is a regular event without a signature. The rumor is serialized to JSON, encrypted, and placed in the <code>content</code> of a seal. The author signs the seal. The seal is then serialized to JSON, encrypted, and placed in the <code>content</code> of a gift wrap, which a random one-time key signs.</p>61 <p>Each layer isolates one concern. The rumor carries the content but has no signature. If it leaks, relays and clients reject it, and nobody can authenticate it. That gives the author deniability. The seal proves who wrote the message but reveals nothing about the content or the recipient. The gift wrap adds routing metadata — the recipient, tags, a different author — without revealing the true author.</p>62 <p>This NIP does <em>not</em> define a messaging protocol. Applications build on it separately; <a href="17.html">NIP-17</a> private messages are the main example. All encryption follows the versioned algorithms of <a href="44.html">NIP-44</a>.</p>6364 <div class="box hint">65 <span class="tag">Hint!</span>66 <p>Think of a paper letter. The rumor is the unsigned note inside. The seal is the signed envelope that hides the note. The gift wrap is the plain shipping box with only the delivery address on it.</p>67 </div>6869 <figure class="diagram">70 <div class="frame">71 <svg viewBox="0 0 560 240" role="img" aria-label="A rumor nests inside a seal, which nests inside a gift wrap; each layer reveals less">72 <rect class="d-actor" x="10" y="20" width="320" height="200" rx="10"/>73 <text class="d-actor-label" x="24" y="44">GIFT WRAP - kind 1059</text>74 <rect class="d-actor" x="40" y="62" width="260" height="128" rx="8"/>75 <text class="d-actor-label" x="54" y="86">SEAL - kind 13</text>76 <rect x="70" y="104" width="200" height="56" rx="6" fill="#f26a00"/>77 <text class="d-label" x="170" y="128" text-anchor="middle" fill="#fff">RUMOR - any kind</text>78 <text class="d-note" x="170" y="146" text-anchor="middle" fill="#fff">unsigned event</text>79 <path class="d-msg" d="M332,44 L378,44"/>80 <text class="d-note" x="384" y="40">public: recipient p tag,</text>81 <text class="d-note" x="384" y="54">one-time signer key</text>82 <path class="d-msg" d="M302,86 L378,86"/>83 <text class="d-note" x="384" y="82">encrypted once: reveals</text>84 <text class="d-note" x="384" y="96">the true author only</text>85 <path class="d-msg" d="M272,132 L378,132"/>86 <text class="d-note" x="384" y="128">encrypted twice: content,</text>87 <text class="d-note" x="384" y="142">kind, tags all hidden</text>88 <text class="d-note" x="384" y="176">deniable: no signature,</text>89 <text class="d-note" x="384" y="190">cannot be authenticated</text>90 </svg>91 </div>92 <figcaption>Fig. 59-1 — <b>Three layers.</b> Each shell hides everything inside it. Only the outermost shell is public.</figcaption>93 </figure>9495 <div class="tscroll"><table class="ref">96 <caption>Kinds defined by this NIP</caption>97 <tr><th>Kind</th><th>Name</th><th>Storage class</th><th>Signed by</th></tr>98 <tr><td class="btn">—</td><td>rumor</td><td>never published as-is</td><td>nobody — unsigned</td></tr>99 <tr><td class="btn">13</td><td>seal</td><td>regular</td><td>the true author's key</td></tr>100 <tr><td class="btn">1059</td><td>gift wrap</td><td>regular</td><td>a random one-time key</td></tr>101 <tr><td class="btn">21059</td><td>ephemeral gift wrap</td><td>ephemeral — relays must not store it</td><td>a random one-time key</td></tr>102 </table></div>103104 <h2 class="bar" id="spec"><span class="num">2</span> The Rumor</h2>105 <p>A rumor is the same thing as an unsigned event. Take any event kind and remove the <code>sig</code> field. The result is a rumor. All other <a href="01.html">NIP-01</a> fields stay, including the computed <code>id</code>.</p>106 <p>Because the rumor has no signature, a leaked rumor cannot be verified. Relays reject it. Clients reject it. This is intentional: it gives the author a measure of deniability.</p>107108 <h2 class="bar"><span class="num">3</span> The Seal — Kind 13</h2>109 <p>A seal is a <code>kind:13</code> event. It wraps one rumor with the sender's regular key. Encrypt the JSON-encoded rumor to the receiver's pubkey and place the ciphertext in <code>content</code>. Then sign the seal with the author's real key.</p>110 <div class="crt">111 <div class="titlebar">Wire format - seal (kind 13)</div>112<pre>{113 <span class="k">"id"</span>: <span class="c">&lt;id&gt;</span>,114 <span class="k">"pubkey"</span>: <span class="c">&lt;real author's pubkey&gt;</span>,115 <span class="k">"content"</span>: <span class="c">&lt;encrypted rumor&gt;</span>,116 <span class="k">"kind"</span>: 13,117 <span class="k">"created_at"</span>: 1686840217,118 <span class="k">"tags"</span>: [],119 <span class="k">"sig"</span>: <span class="c">&lt;signature by the real author's key&gt;</span>120}</pre>121 </div>122 <div class="tscroll"><table class="ref">123 <caption>Seal rules</caption>124 <tr><th>Field</th><th>Rule</th></tr>125 <tr><td class="btn">tags</td><td>MUST always be empty in a <code>kind:13</code>. No <code>p</code> tag points to the receiver.</td></tr>126 <tr><td class="btn">content</td><td>The NIP-44 ciphertext of the JSON-encoded rumor. The seal is <strong>always</strong> encrypted to a receiver's pubkey.</td></tr>127 <tr><td class="btn">pubkey</td><td>The real author's pubkey. This is the only public information in a seal.</td></tr>128 <tr><td class="btn">sig</td><td>Made with the real author's key.</td></tr>129 <tr><td class="btn">inner event</td><td>MUST always be unsigned. A seal wraps a rumor, never a signed event.</td></tr>130 </table></div>131 <p>Without the receiver's or the sender's private key, there is no way to know who the rumor is for. An observer learns only who signed the seal, not what was said.</p>132133 <h2 class="bar"><span class="num">4</span> The Gift Wrap — Kinds 1059 and 21059</h2>134 <p>A gift wrap is a <code>kind:1059</code> event. It can wrap any other event; in this protocol it wraps a seal. Encrypt the JSON-encoded seal with an ephemeral, single-use random key. Place the ciphertext in <code>content</code>, and sign the wrap with that same random key.</p>135 <p>The <code>tags</code> SHOULD include any information needed to route the event to its intended recipient. That includes the recipient's <code>p</code> tag, or <a href="13.html">NIP-13</a> proof of work.</p>136 <div class="crt">137 <div class="titlebar">Wire format - gift wrap (kind 1059)</div>138<pre>{139 <span class="k">"id"</span>: <span class="c">&lt;id&gt;</span>,140 <span class="k">"pubkey"</span>: <span class="c">&lt;random, one-time-use pubkey&gt;</span>,141 <span class="k">"content"</span>: <span class="c">&lt;encrypted kind 13&gt;</span>,142 <span class="k">"kind"</span>: 1059,143 <span class="k">"created_at"</span>: 1686840217,144 <span class="k">"tags"</span>: [[<span class="s">"p"</span>, <span class="c">&lt;recipient pubkey&gt;</span>]],145 <span class="k">"sig"</span>: <span class="c">&lt;signature by the random, one-time-use key&gt;</span>146}</pre>147 </div>148 <p>An <strong>ephemeral gift wrap</strong> is a <code>kind:21059</code> event. It has the same structure as <code>kind:1059</code> — same fields, same <code>p</code> tag, same one-time key — but it follows ephemeral event semantics. Relays MUST NOT store it.</p>149 <p>Pick the kind by delivery need. <code>kind:1059</code> serves regular direct messages and asynchronous communication, where message persistence and offline delivery are expected — as in <a href="17.html">NIP-17</a>. <code>kind:21059</code> serves real-time applications with no asynchronous needs, where messages only matter to currently connected recipients — live chat or real-time gaming.</p>150151 <div class="box warn">152 <span class="tag">Warning!</span>153 <p>Never sign a gift wrap with a real identity key. The whole point of the random one-time key is that the wrap reveals nothing about the true author. Generate a fresh key per wrap and discard it.</p>154 </div>155156 <h2 class="bar"><span class="num">5</span> Encrypting Payloads</h2>157 <p>Encrypt with <a href="44.html">NIP-44</a>, applied to the JSON-encoded event. Place the encryption payload in the <code>content</code> of the wrapper event — either the seal or the gift wrap. The seal uses the conversation key between the author's private key and the recipient's public key. The wrap uses the conversation key between the random one-time key and the recipient's public key. The recipient can therefore decrypt both layers with one private key.</p>158159 <figure class="diagram">160 <div class="frame">161 <svg viewBox="0 0 560 320" role="img" aria-label="Sequence: sender authenticates and publishes a gift wrap; recipient authenticates, requests kind 1059 by p tag, receives the wrap, and decrypts twice">162 <line class="d-wire" x1="95" y1="42" x2="95" y2="300" stroke-dasharray="3 4"/>163 <line class="d-wire" x1="280" y1="42" x2="280" y2="300" stroke-dasharray="3 4"/>164 <line class="d-wire" x1="465" y1="42" x2="465" y2="300" stroke-dasharray="3 4"/>165 <rect class="d-actor" x="45" y="10" width="100" height="30" rx="6"/>166 <text class="d-actor-label" x="95" y="30" text-anchor="middle">Sender</text>167 <rect class="d-actor" x="230" y="10" width="100" height="30" rx="6"/>168 <text class="d-actor-label" x="280" y="30" text-anchor="middle">Relay</text>169 <rect class="d-actor" x="415" y="10" width="100" height="30" rx="6"/>170 <text class="d-actor-label" x="465" y="30" text-anchor="middle">Recipient</text>171 <path class="d-msg" d="M95,68 L275,68"/>172 <text class="d-label" x="185" y="61" text-anchor="middle">AUTH (NIP-42, if required)</text>173 <path class="d-msg d-flow" d="M95,104 L275,104"/>174 <text class="d-label" x="185" y="97" text-anchor="middle">["EVENT", {kind 1059 wrap}]</text>175 <path class="d-msg" d="M465,146 L285,146"/>176 <text class="d-label" x="375" y="139" text-anchor="middle">AUTH — prove you are the p tag</text>177 <path class="d-msg" d="M465,182 L285,182"/>178 <text class="d-label" x="375" y="175" text-anchor="middle">["REQ", "dm", {"kinds":[1059], "#p":[me]}]</text>179 <path class="d-msg blue d-flow" d="M280,220 L460,220"/>180 <text class="d-label" x="375" y="213" text-anchor="middle">["EVENT", "dm", {wrap}]</text>181 <text class="d-note" x="465" y="252" text-anchor="middle">decrypt content → seal (kind 13)</text>182 <text class="d-note" x="465" y="268" text-anchor="middle">decrypt again → rumor</text>183 <text class="d-note" x="95" y="252" text-anchor="middle">signs with one-time key,</text>184 <text class="d-note" x="95" y="268" text-anchor="middle">then discards it</text>185 <circle r="4" fill="#f26a00">186 <animateMotion dur="2.6s" repeatCount="indefinite" path="M95,104 L275,104"/>187 </circle>188 <circle r="4" fill="#2e5f9e">189 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M280,220 L460,220"/>190 </circle>191 </svg>192 </div>193 <figcaption>Fig. 59-2 — <b>Delivery flow.</b> The relay only ever sees a wrap signed by a throwaway key. The recipient peels two layers with one private key.</figcaption>194 </figure>195196 <h2 class="bar"><span class="num">6</span> Spam Protection</h2>197 <p>Gift wraps are signed by random one-time keys. A relay therefore cannot apply pubkey-based anti-spam or anti-sybil measures — reputation, trust scores, or rate limits by key. To mitigate this, a relay may enforce a <a href="42.html">NIP-42</a> <code>auth-required</code> policy and authenticate clients before it accepts gift wraps.</p>198 <p>Clients SHOULD support authenticating to such relays with the user's real identity. NIP-42 authentication is ephemeral: it is not recorded in the event signature. It therefore does not fully undermine the privacy or deniability properties of gift wrapping.</p>199 <p>Clients MAY also attach proof of work to the wrapper event per <a href="13.html">NIP-13</a>. This demonstrates that the event is not spam or a denial-of-service attack.</p>200201 <h2 class="bar"><span class="num">7</span> Deniability, Grouping, and Timestamps</h2>202 <p><strong>Multiple recipients.</strong> A gift wrap addresses one recipient. If a rumor is intended for more than one party, or if the author wants to keep an encrypted copy, wrap and address the same rumor once per recipient. Each party gets an individually encrypted wrap of the same inner event.</p>203204 <figure class="diagram">205 <div class="frame">206 <svg viewBox="0 0 560 190" role="img" aria-label="One rumor is sealed once, then wrapped separately for each recipient and for the author's own copy">207 <rect x="10" y="70" width="120" height="50" rx="8" fill="#f26a00"/>208 <text class="d-label" x="70" y="92" text-anchor="middle" fill="#fff">rumor + seal</text>209 <text class="d-note" x="70" y="108" text-anchor="middle" fill="#fff">one inner event</text>210 <rect class="d-actor" x="330" y="12" width="180" height="42" rx="8"/>211 <text class="d-actor-label" x="420" y="31" text-anchor="middle">Wrap → recipient A</text>212 <text class="d-note" x="420" y="46" text-anchor="middle">p = A, fresh one-time key</text>213 <rect class="d-actor" x="330" y="74" width="180" height="42" rx="8"/>214 <text class="d-actor-label" x="420" y="93" text-anchor="middle">Wrap → recipient B</text>215 <text class="d-note" x="420" y="108" text-anchor="middle">p = B, fresh one-time key</text>216 <rect class="d-actor" x="330" y="136" width="180" height="42" rx="8"/>217 <text class="d-actor-label" x="420" y="155" text-anchor="middle">Wrap → self</text>218 <text class="d-note" x="420" y="170" text-anchor="middle">author's encrypted copy</text>219 <path class="d-msg d-flow" d="M132,82 C220,60 250,42 327,34"/>220 <path class="d-msg d-flow" d="M132,95 L327,95"/>221 <path class="d-msg d-flow" d="M132,108 C220,130 250,148 327,156"/>222 </svg>223 </div>224 <figcaption>Fig. 59-3 — <b>Fan-out.</b> One rumor, many wraps. Every recipient — including the author — gets a separately keyed package.</figcaption>225 </figure>226227 <p><strong>Timestamps.</strong> The canonical <code>created_at</code> time belongs to the rumor. Tweak all other timestamps — on the seal and on the wrap — to thwart time-analysis attacks. Some relays refuse events dated in the future, so all timestamps SHOULD be in the past. When you add <a href="40.html">NIP-40</a> expiration tags to both the seal and gift wrap layers, use independent random timestamps for each layer. Different <code>created_at</code> values increase timing variance and protect against metadata correlation attacks.</p>228 <p><strong>Relay policy.</strong> Relays may choose not to store gift wrapped events, because they are not publicly useful. To protect recipient metadata, relays SHOULD guard access to <code>kind 1059</code> events based on user AUTH, and SHOULD only serve them to the marked recipient. When possible, clients should only send wrapped events to <code>read</code> relays for the recipient that implement AUTH and that refuse to serve wraps to non-recipients.</p>229 <p><strong>Cleanup.</strong> Since signing keys are random, the recipient is the only stable identity on a wrap. Relays SHOULD delete <code>kind:1059</code> events whose <code>p</code> tag matches the signer of <a href="09.html">NIP-09</a> deletion requests or <a href="62.html">NIP-62</a> vanish requests.</p>230231 <div class="box tech">232 <span class="tag">Tech Note</span>233 <p>The source spec contradicts itself on seal tags. Section 2 states that tags MUST always be empty in a <code>kind:13</code>, but the considerations section advises adding expiration tags "to both <code>seal</code> and <code>gift wrap</code> layers". An expiration tag on the seal violates the empty-tags rule as written. The spec does not resolve this; the safe reading is to put expiration tags on the wrap only.</p>234 </div>235236 <h2 class="bar" id="examples"><span class="num">8</span> Worked Example</h2>237 <p>Send a wrapped <code>kind 1</code> note between two parties. The message is "Are you going to the party tonight?". Do not use this exact scheme in practice — it is only a demonstration. Refer to other NIPs, such as <a href="17.html">NIP-17</a>, for concrete messaging protocols that depend on gift wraps.</p>238 <div class="crt">239 <div class="titlebar">Test keys</div>240<pre><span class="c">-- author private key --</span>2410beebd062ec8735f4243466049d7747ef5d6594ee838de147f8aab842b15e273242<span class="c">-- recipient private key --</span>243e108399bd8424357a710b606ae0c13166d853d327e47a6e5e038197346bdbf45244<span class="c">-- ephemeral wrapper private key --</span>2454f02eac59266002db5801adc5270700ca69d5b8f761d8732fab2fbf233c90cbd</pre>246 </div>247248 <p><strong>Step 1 — create the rumor.</strong> Build a <code>kind 1</code> event with the message and any tags you want. Compute its <code>id</code>. Do not sign it.</p>249 <div class="crt">250 <div class="titlebar">Rumor - unsigned kind 1</div>251<pre>{252 <span class="k">"created_at"</span>: 1691518405,253 <span class="k">"content"</span>: <span class="s">"Are you going to the party tonight?"</span>,254 <span class="k">"tags"</span>: [],255 <span class="k">"kind"</span>: 1,256 <span class="k">"pubkey"</span>: <span class="s">"611df01bfcf85c26ae65453b772d8f1dfd25c264621c0277e1fc1518686faef9"</span>,257 <span class="k">"id"</span>: <span class="s">"9dd003c6d3b73b74a85a9ab099469ce251653a7af76f523671ab828acd2a0ef9"</span>258}</pre>259 </div>260261 <p><strong>Step 2 — seal the rumor.</strong> Derive a NIP-44 conversation key from the author's private key and the recipient's public key. Encrypt the JSON-encoded rumor with it. Place the ciphertext in the <code>content</code> of a <code>kind 13</code> seal. Sign the seal with the author's key. Note the randomized <code>created_at</code>.</p>262 <div class="crt">263 <div class="titlebar">Seal - kind 13, signed by the author</div>264<pre>{265 <span class="k">"content"</span>: <span class="s">"AqBCdwoS7/tPK+QGkPCadJTn8FxGkd24iApo3BR9/M0u…fAZ0f5EYRo9/vKSd8TV0wRb9DQ="</span>,266 <span class="k">"kind"</span>: 13,267 <span class="k">"created_at"</span>: 1703015180,268 <span class="k">"pubkey"</span>: <span class="s">"611df01bfcf85c26ae65453b772d8f1dfd25c264621c0277e1fc1518686faef9"</span>,269 <span class="k">"tags"</span>: [],270 <span class="k">"id"</span>: <span class="s">"28a87d7c074d94a58e9e89bb3e9e4e813e2189f285d797b1c56069d36f59eaa7"</span>,271 <span class="k">"sig"</span>: <span class="s">"02fc3facf6621196c32912b1ef53bac8f8bfe9db51c0e7102c073103586b0d29…4519ad73"</span>272}</pre>273 </div>274275 <p><strong>Step 3 — wrap the seal.</strong> Generate the ephemeral, single-use random key. Encrypt the JSON-encoded seal with it, to the recipient's public key. Place the ciphertext in the <code>content</code> of a <code>kind 1059</code>. Add a single <code>p</code> tag with the recipient's public key. Sign the gift wrap with the random key.</p>276 <div class="crt">277 <div class="titlebar">Gift wrap - kind 1059, signed by a one-time key</div>278<pre>{279 <span class="k">"content"</span>: <span class="s">"AhC3Qj/QsKJFWuf6xroiYip+2yK95qPwJjVvFujhzSgu…15QVqD02JxfLF7nA6sg3UlYgtiGw…"</span>,280 <span class="k">"kind"</span>: 1059,281 <span class="k">"created_at"</span>: 1703021488,282 <span class="k">"pubkey"</span>: <span class="s">"18b1a75918f1f2c90c23da616bce317d36e348bcf5f7ba55e75949319210c87c"</span>,283 <span class="k">"id"</span>: <span class="s">"5c005f3ccf01950aa8d131203248544fb1e41a0d698e846bd419cec3890903ac"</span>,284 <span class="k">"sig"</span>: <span class="s">"35fabdae4634eb630880a1896a886e40fd6ea8a60958e30b89b33a93e6235df7…60f54259"</span>,285 <span class="k">"tags"</span>: [[<span class="s">"p"</span>, <span class="s">"166bf3765ebd1fc55decfe395beff2ea3b2a4e0a8946e7eb578512b555737c99"</span>]]286}</pre>287 </div>288289 <p><strong>Step 4 — broadcast selectively.</strong> Send the <code>kind:1059</code> or <code>kind:21059</code> event to the recipient's relays only. Delete all the other events. The recipient decrypts the wrap with their private key, gets the seal, decrypts again, and reads the rumor.</p>290291 <div class="box tech">292 <span class="tag">Tech Note</span>293 <p>Two defects in the source example. First, step 1 says to create the event "signed by the author" and then immediately says "Do not sign the event" — the second instruction is the correct one. Second, the gift wrap JSON in the source has a trailing comma after the <code>tags</code> line, so it is not valid JSON. The transcript above corrects it.</p>294 </div>295296 <h2 class="bar" id="history"><span class="num">9</span> Version History</h2>297 <p>Gift wrap arrived in 2023 as the privacy layer under the new direct-message design. Notable changes, newest first:</p>298 <ul class="patchnotes">299 <li><span class="ver">2026</span><span class="when">2026-06</span>A change that made <code>id</code> optional on rumors was merged and reverted one day later. Rumors keep their <code>id</code>.</li>300 <li><span class="ver">2026</span><span class="when">2026-05</span>Added the ephemeral gift wrap, <code>kind:21059</code>, for real-time use. Documented <a href="42.html">NIP-42</a> AUTH as the answer to spam from one-time keys.</li>301 <li><span class="ver">2025</span><span class="when">2025-11</span>Relays should delete gift wraps whose <code>p</code> tag matches the signer of <a href="09.html">NIP-09</a> deletions or <a href="62.html">NIP-62</a> vanish requests.</li>302 <li><span class="ver">2025</span><span class="when">2025-10</span>Stronger timestamp guidance: independent random <code>created_at</code> values per layer against correlation attacks.</li>303 <li class="minor"><span class="ver">2024-25</span><span class="when">2024-2025</span>Typo, formatting, and status-line cleanups; the <code>relay</code> tag joined the status header.</li>304 <li><span class="ver">2024</span><span class="when">2024-01</span>Removed the <code>p</code> tag from the seal. Clarified that NIP-59 defines no messaging protocol on its own.</li>305 <li><span class="ver">Origin</span><span class="when">2023-08</span>Jonathan Staab introduced gift wrap: rumor, seal, and wrap as three layers over <a href="44.html">NIP-44</a> encryption.</li>306 </ul>307308 <div class="credits">309 <h3 class="cardhead">Original Proposal - Credits</h3>310 <table>311 <tr><td>Author</td><td>Jonathan Staab</td></tr>312 <tr><td>First commit</td><td>2023-08-11 — “Introduce NIP-59 gift wrap”</td></tr>313 <tr><td>Status</td><td>active - optional — with relay-side behavior for kinds 1059 / 21059</td></tr>314 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/59.md">59.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/59.md">full change history</a></td></tr>315 </table>316 </div>317318 <h2 class="bar"><span class="num">10</span> See Also</h2>319 <ul>320 <li><a href="44.html">NIP-44</a> — the versioned encryption used for both the seal and the wrap. Required.</li>321 <li><a href="17.html">NIP-17</a> — private direct messages, the main protocol built on gift wraps.</li>322 <li><a href="01.html">NIP-01</a> — the base event format; a rumor is a NIP-01 event minus its signature.</li>323 <li><a href="42.html">NIP-42</a> — client-to-relay AUTH, used to gate access to kind 1059 and fight spam.</li>324 <li><a href="13.html">NIP-13</a> — proof of work that a client may attach to a wrapper event.</li>325 <li><a href="40.html">NIP-40</a> — expiration tags referenced by the timestamp guidance.</li>326 <li><a href="09.html">NIP-09</a> — deletion requests that trigger gift wrap cleanup on relays.</li>327 <li><a href="62.html">NIP-62</a> — vanish requests, the stronger form of the same cleanup.</li>328 </ul>329 </div>330331 <aside>332 <div class="cartridge">333 <div class="inner">334 <h3 class="cardhead">Spec Card</h3>335 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>336 <dl>337 <dt>Status</dt><dd><span class="chip final">active</span><span class="chip">optional</span><span class="chip">relay</span></dd>338 <dt>Defines</dt><dd>rumor (unsigned event) - seal - gift wrap - ephemeral gift wrap</dd>339 <dt>Kinds</dt><dd>13 - 1059 - 21059</dd>340 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="44.html">NIP-44</a></dd>341 <dt>Plays well with</dt><dd><a href="42.html">NIP-42</a> AUTH - <a href="13.html">NIP-13</a> PoW</dd>342 <dt>Crypto</dt><dd>NIP-44 v2 - one-time secp256k1 keys</dd>343 <dt>First commit</dt><dd>2023-08-11</dd>344 <dt>Last updated</dt><dd>2026-06-02</dd>345 </dl>346 </div>347 </div>348 </aside>349 </main>350351 <nav class="navbtns">352 <a href="58.html">◀ NIP-58: Badges</a>353 <a href="5a.html">NIP-5A: Static Websites (nsites) ▶</a>354 </nav>355356 <footer class="pagefoot">357 <a href="../index.html">Nostr Protocol Manual</a>358 <span class="pageno">NIP 59 / F4</span>359 </footer>360</div>361362<script src="../assets/webmcp.js" defer></script>363</body>364</html>