# How Buzz Handles NIP-17 Gift Wraps and NIP-44 Encrypted DMs in Nostr

> Learn how Buzz handles NIP-17 gift wraps with ephemeral-key signed events and NIP-44 encryption for private payloads. Explore its approach to Nostr DMs.

- Repository: [Block Open Source/buzz](https://github.com/block/buzz)
- Tags: internals
- Published: 2026-08-29

---

**Buzz implements NIP-17 gift-wrapped DMs through ephemeral-key signed events with strict p-tag filtering while maintaining NIP-44 encryption capabilities for other private payloads, though direct NIP-44 DMs remain unimplemented.**

The **block/buzz** repository provides a relay-first Nostr client that treats privacy-enhancing direct message protocols with distinct architectural approaches. Understanding how Buzz handles **NIP-17 gift wraps and NIP-44 encrypted DMs** reveals important implementation patterns for developers building privacy-preserving messaging on Nostr.

## NIP-17 Gift-Wrapped Direct Messages Implementation

Buzz treats NIP-17 gift-wraps as **opaque envelopes** that protect sender identity while ensuring targeted delivery.

### Ephemeral Key Signing and Relay Verification

Gift-wrap events use **kind:1059** and are signed with an ephemeral key rather than the author's permanent identity key. This allows the relay to verify event authenticity without learning the author's identity. In [`crates/buzz-relay/src/handlers/ingest.rs`](https://github.com/block/buzz/blob/main/crates/buzz-relay/src/handlers/ingest.rs), the relay bypasses the normal author-pubkey check for these events, instead validating only the presence of a `#p` tag containing the recipient's public key.

### P-Gate Filtering for Privacy

The relay enforces strict **p-gate filtering** to prevent metadata leakage. Subscriptions must include a matching `#p` filter to receive gift-wrap events. The implementation in [`crates/buzz-relay/src/handlers/req.rs`](https://github.com/block/buzz/blob/main/crates/buzz-relay/src/handlers/req.rs) contains the function `p_gate_rejects_bare_kind_search_filter_for_gift_wrap`, which explicitly rejects queries attempting to search gift-wraps without specifying a recipient pubkey.

Push runtime matching follows the same constraint. The function `gift_wrap_match_requires_self_p_filter_and_recipient` in [`crates/buzz-relay/src/push_runtime.rs`](https://github.com/block/buzz/blob/main/crates/buzz-relay/src/push_runtime.rs) ensures that a lease can only match gift-wraps addressed to its own author, preventing unauthorized interception.

### Indexing and Search Restrictions

Gift-wraps receive **no full-text indexing** and remain invisible to NIP-50 search. The relay explicitly excludes these events from generic `kind` searches to prevent correlation attacks. End-to-end tests in [`crates/buzz-test-client/tests/e2e_nostr_interop.rs`](https://github.com/block/buzz/blob/main/crates/buzz-test-client/tests/e2e_nostr_interop.rs) assert that created gift-wraps never appear in search results, confirming the privacy guarantee.

### Sending NIP-17 Gift-Wraps

The following Rust code demonstrates creating and sending a gift-wrap event using the Buzz SDK:

```rust
use buzz_sdk::builders::EventBuilder;
use buzz_sdk::kind::Kind;

// Create a unique payload
let payload = format!("gift‑wrap‑{}", uuid::Uuid::new_v4());

// Build a gift-wrap event (kind 1059) addressed to recipient B
let gift_wrap = EventBuilder::new(Kind::Custom(1059), &payload)
    .add_tag(["p", recipient_pubkey])
    .expect("sign gift wrap");

// Send via a connected client
let ok = client.send_event(gift_wrap).await.expect("send gift wrap");
assert!(ok.accepted, "relay rejected gift wrap: {}", ok.message);

```

According to the source code at [`crates/buzz-test-client/tests/e2e_nostr_interop.rs`](https://github.com/block/buzz/blob/main/crates/buzz-test-client/tests/e2e_nostr_interop.rs) (lines 602-725), this pattern successfully delivers events to intended recipients while maintaining sender anonymity.

## NIP-44 Encryption Support and Current Limitations

While Buzz does not currently implement NIP-44 for direct messaging, the cryptographic infrastructure exists for other private payloads.

### Where NIP-44 is Currently Used

Buzz utilizes **NIP-44 v2 encryption** extensively for non-DM private data:

- **Reminders**: Events of `kind:30300` (NIP-ER) encrypt reminder bodies using NIP-44
- **Agent memory**: Events of `kind:30174` (NIP-AE) encrypt engrams to the owner-agent conversation key
- **Desktop storage**: Locked envelopes and persona cards in the Tauri side store use NIP-44 for encrypting sensitive snapshots and manifests

### Mobile Crypto Implementation

The mobile crypto library at `mobile/lib/shared/crypto/nip44.dart` provides the complete NIP-44 v2 implementation. The `encrypt` function derives the conversation key via ECDH, then applies XChaCha20-Poly1305 authenticated encryption. The corresponding `decrypt` function verifies the version byte, HMAC, and payload length before returning plaintext.

### Payload Limits and Specifications

NIP-44 payloads in Buzz are capped at **65,535 bytes** of plaintext. The relay enforces a 256 KB total content limit, providing sufficient headroom for encryption overhead. Self-encryption patterns support "encrypt-to-self" use cases where the same key pair handles both encryption and decryption for personal data like reminders.

### Encrypting with NIP-44 in Dart

The following Flutter/Dart example shows NIP-44 encryption for private payloads:

```dart
import 'package:buzz_shared/crypto/nip44.dart';

final privKey = Hex.decode('...'); // your private key
final pubKey  = Hex.decode('...'); // recipient's public key
final plaintext = utf8.encode('Hello, encrypted DM!');

// Derive conversation key & encrypt
final ciphertext = await NIP44.encrypt(privKey, pubKey, plaintext);

// Decrypt (recipient)
final decrypted = await NIP44.decrypt(pubKey, privKey, ciphertext);
assert(utf8.decode(decrypted) == 'Hello, encrypted DM!');

```

As documented in [`NOSTR.md`](https://github.com/block/buzz/blob/main/NOSTR.md), direct NIP-44 DM support remains on the roadmap, potentially as a new kind such as `kind:10050`.

## Summary

- **NIP-17 gift-wraps** (kind:1059) in Buzz use ephemeral keys and strict p-tag filtering to enable anonymous, targeted delivery without search indexing
- The relay enforces privacy through `p_gate_rejects_bare_kind_search_filter_for_gift_wrap` and related functions that require recipient-specific subscriptions
- **NIP-44 encryption** is fully implemented for reminders, agent memory, and storage, but not yet available for direct messaging between users
- Mobile and desktop clients share the NIP-44 v2 implementation using XChaCha20-Poly1305 via `mobile/lib/shared/crypto/nip44.dart`
- Executors must ignore encrypted payloads within gift-wraps and use only outer-envelope fields for matching, as specified in [`docs/nips/NIP-PL.md`](https://github.com/block/buzz/blob/main/docs/nips/NIP-PL.md)

## Frequently Asked Questions

### What is the difference between NIP-17 and NIP-44 in Buzz?

**NIP-17** provides the transport mechanism for anonymous DMs using gift-wrap envelopes (kind:1059), while **NIP-44** provides the encryption algorithm for message content. Buzz currently uses NIP-17 gift-wraps to deliver opaque payloads, which may contain NIP-44 encrypted content, but does not yet support native NIP-44 DMs as a standalone message type.

### Why are NIP-17 gift-wraps not searchable in Buzz?

Buzz explicitly excludes gift-wraps from the NIP-50 full-text search index to prevent metadata correlation attacks. The end-to-end tests verify that gift-wraps never appear in search results, ensuring that only recipients with explicit knowledge of the event ID or real-time subscription filters can access these messages.

### How does Buzz verify NIP-17 gift-wrap authenticity without revealing the sender?

The relay validates the cryptographic signature using an **ephemeral key** generated specifically for that event, rather than the author's permanent identity key. As implemented in [`crates/buzz-relay/src/handlers/ingest.rs`](https://github.com/block/buzz/blob/main/crates/buzz-relay/src/handlers/ingest.rs), the relay skips the standard author-pubkey verification and instead validates only the structural integrity and recipient p-tag, allowing authentication without identity disclosure.

### When will Buzz support native NIP-44 encrypted DMs?

According to [`NOSTR.md`](https://github.com/block/buzz/blob/main/NOSTR.md), NIP-44 encrypted DMs remain on the development roadmap, potentially implemented as a new kind (such as `kind:10050`). Until then, users seeking private messaging should rely on NIP-17 gift-wraps, which can optionally contain NIP-44 encrypted payloads for end-to-end encryption.