Chapter 59 - Encryption
59
Nostr Implementation Possibility - Hex № 59

Gift Wrap

Hide any event inside two layers of encryption, so relays see a package but never the sender, the content, or the conversation.

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.

Hint!

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.

GIFT WRAP - kind 1059 SEAL - kind 13 RUMOR - any kind unsigned event public: recipient p tag, one-time signer key encrypted once: reveals the true author only encrypted twice: content, kind, tags all hidden deniable: no signature, cannot be authenticated
Fig. 59-1 — Three layers. Each shell hides everything inside it. Only the outermost shell is public.
Kinds defined by this NIP
KindNameStorage classSigned by
—rumornever published as-isnobody — unsigned
13sealregularthe true author's key
1059gift wrapregulara random one-time key
21059ephemeral gift wrapephemeral — relays must not store ita 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.

Wire format - seal (kind 13)
{
  "id":         <id>,
  "pubkey":     <real author's pubkey>,
  "content":    <encrypted rumor>,
  "kind":       13,
  "created_at": 1686840217,
  "tags":       [],
  "sig":        <signature by the real author's key>
}
Seal rules
FieldRule
tagsMUST always be empty in a kind:13. No p tag points to the receiver.
contentThe NIP-44 ciphertext of the JSON-encoded rumor. The seal is always encrypted to a receiver's pubkey.
pubkeyThe real author's pubkey. This is the only public information in a seal.
sigMade with the real author's key.
inner eventMUST 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.

Wire format - gift wrap (kind 1059)
{
  "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.

Warning!

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.

Sender Relay Recipient AUTH (NIP-42, if required) ["EVENT", {kind 1059 wrap}] AUTH — prove you are the p tag ["REQ", "dm", {"kinds":[1059], "#p":[me]}] ["EVENT", "dm", {wrap}] decrypt content → seal (kind 13) decrypt again → rumor signs with one-time key, then discards it
Fig. 59-2 — Delivery flow. The relay only ever sees a wrap signed by a throwaway key. The recipient peels two 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.

rumor + seal one inner event Wrap → recipient A p = A, fresh one-time key Wrap → recipient B p = B, fresh one-time key Wrap → self author's encrypted copy
Fig. 59-3 — Fan-out. One rumor, many wraps. Every recipient — including the author — gets a separately keyed package.

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.

Tech Note

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.

Test keys
-- 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.

Rumor - unsigned kind 1
{
  "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.

Seal - kind 13, signed by the author
{
  "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.

Gift wrap - kind 1059, signed by a one-time 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.

Tech Note

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 id optional on rumors was merged and reverted one day later. Rumors keep their id.
  • 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 p tag matches the signer of NIP-09 deletions or NIP-62 vanish requests.
  • 20252025-10Stronger timestamp guidance: independent random created_at values per layer against correlation attacks.
  • 2024-252024-2025Typo, formatting, and status-line cleanups; the relay tag joined the status header.
  • 20242024-01Removed the p tag 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

AuthorJonathan Staab
First commit2023-08-11 — “Introduce NIP-59 gift wrap”
Statusactive - optional — with relay-side behavior for kinds 1059 / 21059
Source59.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.