1 Overview
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.
The protocol stacks three concepts: the rumor, the seal, and the gift wrap. A rumor is a regular event without a signature. The rumor is serialized to JSON, encrypted, and placed in the content of a seal. The author signs the seal. The seal is then serialized to JSON, encrypted, and placed in the content of a gift wrap, which a random one-time key signs.
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.
This NIP does not define a messaging protocol. Applications build on it separately; NIP-17 private messages are the main example. All encryption follows the versioned algorithms of NIP-44.
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.
| Kind | Name | Storage class | Signed by |
|---|---|---|---|
| — | rumor | never published as-is | nobody — unsigned |
| 13 | seal | regular | the true author's key |
| 1059 | gift wrap | regular | a random one-time key |
| 21059 | ephemeral gift wrap | ephemeral — relays must not store it | a random one-time key |
2 The Rumor
A rumor is the same thing as an unsigned event. Take any event kind and remove the sig field. The result is a rumor. All other NIP-01 fields stay, including the computed id.
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.
3 The Seal — Kind 13
A seal is a kind:13 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 content. Then sign the seal with the author's real key.
{
"id": <id>,
"pubkey": <real author's pubkey>,
"content": <encrypted rumor>,
"kind": 13,
"created_at": 1686840217,
"tags": [],
"sig": <signature by the real author's key>
}
| Field | Rule |
|---|---|
| tags | MUST always be empty in a kind:13. No p tag points to the receiver. |
| content | The NIP-44 ciphertext of the JSON-encoded rumor. The seal is always encrypted to a receiver's pubkey. |
| pubkey | The real author's pubkey. This is the only public information in a seal. |
| sig | Made with the real author's key. |
| inner event | MUST always be unsigned. A seal wraps a rumor, never a signed event. |
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.
4 The Gift Wrap — Kinds 1059 and 21059
A gift wrap is a kind:1059 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 content, and sign the wrap with that same random key.
The tags SHOULD include any information needed to route the event to its intended recipient. That includes the recipient's p tag, or NIP-13 proof of work.
{
"id": <id>,
"pubkey": <random, one-time-use pubkey>,
"content": <encrypted kind 13>,
"kind": 1059,
"created_at": 1686840217,
"tags": [["p", <recipient pubkey>]],
"sig": <signature by the random, one-time-use key>
}
An ephemeral gift wrap is a kind:21059 event. It has the same structure as kind:1059 — same fields, same p tag, same one-time key — but it follows ephemeral event semantics. Relays MUST NOT store it.
Pick the kind by delivery need. kind:1059 serves regular direct messages and asynchronous communication, where message persistence and offline delivery are expected — as in NIP-17. kind:21059 serves real-time applications with no asynchronous needs, where messages only matter to currently connected recipients — live chat or real-time gaming.
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.
5 Encrypting Payloads
Encrypt with NIP-44, applied to the JSON-encoded event. Place the encryption payload in the content 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.
6 Spam Protection
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 NIP-42 auth-required policy and authenticate clients before it accepts gift wraps.
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.
Clients MAY also attach proof of work to the wrapper event per NIP-13. This demonstrates that the event is not spam or a denial-of-service attack.
7 Deniability, Grouping, and Timestamps
Multiple recipients. 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.
Timestamps. The canonical created_at 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 NIP-40 expiration tags to both the seal and gift wrap layers, use independent random timestamps for each layer. Different created_at values increase timing variance and protect against metadata correlation attacks.
Relay policy. Relays may choose not to store gift wrapped events, because they are not publicly useful. To protect recipient metadata, relays SHOULD guard access to kind 1059 events based on user AUTH, and SHOULD only serve them to the marked recipient. When possible, clients should only send wrapped events to read relays for the recipient that implement AUTH and that refuse to serve wraps to non-recipients.
Cleanup. Since signing keys are random, the recipient is the only stable identity on a wrap. Relays SHOULD delete kind:1059 events whose p tag matches the signer of NIP-09 deletion requests or NIP-62 vanish requests.
The source spec contradicts itself on seal tags. Section 2 states that tags MUST always be empty in a kind:13, but the considerations section advises adding expiration tags "to both seal and gift wrap 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.
8 Worked Example
Send a wrapped kind 1 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 NIP-17, for concrete messaging protocols that depend on gift wraps.
-- author private key -- 0beebd062ec8735f4243466049d7747ef5d6594ee838de147f8aab842b15e273 -- recipient private key -- e108399bd8424357a710b606ae0c13166d853d327e47a6e5e038197346bdbf45 -- ephemeral wrapper private key -- 4f02eac59266002db5801adc5270700ca69d5b8f761d8732fab2fbf233c90cbd
Step 1 — create the rumor. Build a kind 1 event with the message and any tags you want. Compute its id. Do not sign it.
{
"created_at": 1691518405,
"content": "Are you going to the party tonight?",
"tags": [],
"kind": 1,
"pubkey": "611df01bfcf85c26ae65453b772d8f1dfd25c264621c0277e1fc1518686faef9",
"id": "9dd003c6d3b73b74a85a9ab099469ce251653a7af76f523671ab828acd2a0ef9"
}
Step 2 — seal the rumor. 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 content of a kind 13 seal. Sign the seal with the author's key. Note the randomized created_at.
{
"content": "AqBCdwoS7/tPK+QGkPCadJTn8FxGkd24iApo3BR9/M0u…fAZ0f5EYRo9/vKSd8TV0wRb9DQ=",
"kind": 13,
"created_at": 1703015180,
"pubkey": "611df01bfcf85c26ae65453b772d8f1dfd25c264621c0277e1fc1518686faef9",
"tags": [],
"id": "28a87d7c074d94a58e9e89bb3e9e4e813e2189f285d797b1c56069d36f59eaa7",
"sig": "02fc3facf6621196c32912b1ef53bac8f8bfe9db51c0e7102c073103586b0d29…4519ad73"
}
Step 3 — wrap the seal. 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 content of a kind 1059. Add a single p tag with the recipient's public key. Sign the gift wrap with the random key.
{
"content": "AhC3Qj/QsKJFWuf6xroiYip+2yK95qPwJjVvFujhzSgu…15QVqD02JxfLF7nA6sg3UlYgtiGw…",
"kind": 1059,
"created_at": 1703021488,
"pubkey": "18b1a75918f1f2c90c23da616bce317d36e348bcf5f7ba55e75949319210c87c",
"id": "5c005f3ccf01950aa8d131203248544fb1e41a0d698e846bd419cec3890903ac",
"sig": "35fabdae4634eb630880a1896a886e40fd6ea8a60958e30b89b33a93e6235df7…60f54259",
"tags": [["p", "166bf3765ebd1fc55decfe395beff2ea3b2a4e0a8946e7eb578512b555737c99"]]
}
Step 4 — broadcast selectively. Send the kind:1059 or kind:21059 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.
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 tags line, so it is not valid JSON. The transcript above corrects it.
9 Version History
Gift wrap arrived in 2023 as the privacy layer under the new direct-message design. Notable changes, newest first:
- 20262026-06A change that made
idoptional on rumors was merged and reverted one day later. Rumors keep theirid. - 20262026-05Added the ephemeral gift wrap,
kind:21059, for real-time use. Documented NIP-42 AUTH as the answer to spam from one-time keys. - 20252025-11Relays should delete gift wraps whose
ptag matches the signer of NIP-09 deletions or NIP-62 vanish requests. - 20252025-10Stronger timestamp guidance: independent random
created_atvalues per layer against correlation attacks. - 2024-252024-2025Typo, formatting, and status-line cleanups; the
relaytag joined the status header. - 20242024-01Removed the
ptag from the seal. Clarified that NIP-59 defines no messaging protocol on its own. - Origin2023-08Jonathan Staab introduced gift wrap: rumor, seal, and wrap as three layers over NIP-44 encryption.
Original Proposal - Credits
| Author | Jonathan Staab |
| First commit | 2023-08-11 — “Introduce NIP-59 gift wrap” |
| Status | active - optional — with relay-side behavior for kinds 1059 / 21059 |
| Source | 59.md on GitHub - full change history |
10 See Also
- NIP-44 — the versioned encryption used for both the seal and the wrap. Required.
- NIP-17 — private direct messages, the main protocol built on gift wraps.
- NIP-01 — the base event format; a rumor is a NIP-01 event minus its signature.
- NIP-42 — client-to-relay AUTH, used to gate access to kind 1059 and fight spam.
- NIP-13 — proof of work that a client may attach to a wrapper event.
- NIP-40 — expiration tags referenced by the timestamp guidance.
- NIP-09 — deletion requests that trigger gift wrap cleanup on relays.
- NIP-62 — vanish requests, the stronger form of the same cleanup.