Nostr.Event.GiftWrap (Nostr Lib v0.2.1) (event) (nip59)

View Source

Gift Wrap event (kind 1059)

A gift wrap event wraps any other event (typically a seal). It uses a random, one-time-use keypair for signing, which obscures the original author's identity. The recipient is identified by a p tag.

Gift wrapping provides the outermost layer of privacy in NIP-59's three-layer protocol:

  • Rumor: unsigned event (deniable)
  • Seal: encrypted rumor, signed by author
  • Gift Wrap: encrypted seal, signed with ephemeral key

Defined in NIP 59 https://github.com/nostr-protocol/nips/blob/master/59.md

Summary

Types

t()

Gift wrap event containing an encrypted seal

Functions

Create a gift wrap from a seal

Parse a kind 1059 event into a GiftWrap struct

Unwrap a gift wrap to extract the seal

Unwrap a gift wrap to extract the original rumor

Wrap a message in a complete gift wrap (rumor → seal → gift wrap)

Types

t()

@type t() :: %Nostr.Event.GiftWrap{
  encrypted_seal: binary(),
  event: Nostr.Event.t(),
  recipient: binary()
}

Gift wrap event containing an encrypted seal

Functions

create(seal, recipient_pubkey, opts \\ [])

@spec create(Nostr.Event.Seal.t(), binary(), Keyword.t()) :: t()

Create a gift wrap from a seal

Encrypts the seal using NIP-44 with a random ephemeral key and the recipient's public key. The gift wrap is signed by the ephemeral key.

Parameters

  • seal: The seal to wrap
  • recipient_pubkey: Recipient's public key (hex-encoded)
  • opts: Optional keyword list:
    • :created_at - override random timestamp
    • :ephemeral_seckey - use specific ephemeral key (for testing)

Example

gift_wrap = GiftWrap.create(seal, recipient_pubkey)

parse(event)

@spec parse(Nostr.Event.t()) :: t() | {:error, String.t(), Nostr.Event.t()}

Parse a kind 1059 event into a GiftWrap struct

Note: This only extracts the encrypted content. Use unwrap/2 to decrypt the seal.

unwrap(gift_wrap, recipient_seckey)

@spec unwrap(t(), binary()) :: {:ok, Nostr.Event.Seal.t()} | {:error, atom()}

Unwrap a gift wrap to extract the seal

Decrypts the gift wrap's content using the recipient's secret key. The ephemeral public key is obtained from the gift wrap event.

Parameters

  • gift_wrap: The gift wrap to unwrap
  • recipient_seckey: Recipient's secret key (hex-encoded)

Returns

  • {:ok, seal} on success
  • {:error, reason} on failure

unwrap_message(gift_wrap, recipient_seckey)

@spec unwrap_message(t(), binary()) :: {:ok, Nostr.Event.Rumor.t()} | {:error, atom()}

Unwrap a gift wrap to extract the original rumor

This is a convenience function that decrypts all layers:

  1. Unwraps the gift wrap to get the seal
  2. Unwraps the seal to get the rumor

Parameters

  • gift_wrap: The gift wrap to unwrap
  • recipient_seckey: Recipient's secret key (hex-encoded)

Returns

  • {:ok, rumor} on success
  • {:error, reason} on failure

Example

{:ok, rumor} = GiftWrap.unwrap_message(gift_wrap, recipient_seckey)
IO.puts(rumor.content)

wrap_message(kind, content, sender_seckey, recipient_pubkey, opts \\ [])

@spec wrap_message(non_neg_integer(), String.t(), binary(), binary(), Keyword.t()) ::
  t()

Wrap a message in a complete gift wrap (rumor → seal → gift wrap)

This is a convenience function that performs all three steps of the NIP-59 protocol:

  1. Creates an unsigned rumor from the message
  2. Seals the rumor with the sender's key
  3. Wraps the seal with an ephemeral key

Parameters

  • kind: The event kind for the inner rumor
  • content: The message content
  • sender_seckey: Sender's secret key (hex-encoded)
  • recipient_pubkey: Recipient's public key (hex-encoded)
  • opts: Optional keyword list:
    • :tags - tags for the inner rumor (default: [])
    • :created_at - timestamp for the rumor (default: now)

Example

gift_wrap = GiftWrap.wrap_message(1, "Hello!", sender_seckey, recipient_pubkey)