NIP-59 gift wrapping
NIP-59 (Nostr Implementation Possibility 59) is a privacy-preserving encryption standard that wraps messages in multiple layers of encryption. Unlike simple end-to-end encryption, gift wrapping:- Hides sender and recipient: Relays only see encrypted envelopes
- Provides forward secrecy: Uses ephemeral keys that can’t be reused
- Protects metadata: Timestamps and other details are obscured
- Seal: Inner layer encrypted to the recipient
- Gift wrap: Outer layer (kind 1059) with randomized metadata
Gift wrapping is the default for all Hoot messages. You don’t need to enable it—every message you send is automatically encrypted.
How messages are encrypted
When you send a message in Hoot, the encryption happens in multiple steps:Step 1: Create the mail event
First, Hoot creates a kind 2024 event with your message content, recipients, and subject. This event is called a “rumor” because it doesn’t have a signature yet.Step 2: Wrap per recipient
Each recipient gets their own encrypted copy. Fromsrc/mail_event.rs:59-68:
If you send a message to 5 people, Hoot creates 5 separate gift-wrapped events—one encrypted for each recipient. This ensures that relays can’t determine who else received the message.
Step 3: Send to relays
Each encrypted event is sent to all connected relays. The relays only see:- A kind 1059 event (gift wrap)
- A recipient public key tag
- Random timestamp (obscured for privacy)
- Encrypted payload
Receiving encrypted messages
When Hoot receives a kind 1059 event from a relay, it attempts to decrypt it:Unwrapping process
Fromsrc/event_processing.rs:368-394:
- Checks recipient: Verifies you have the private key to decrypt
- Decrypts seal: Extracts the inner sealed event
- Validates sender: Ensures the seal was created by the claimed sender
- Verifies rumor ID: Confirms the inner event is valid
- Stores rumor: Saves the decrypted mail event to the database
Hoot stores the decrypted rumor (kind 2024 event) in the database, not the encrypted gift wrap. This allows for efficient searching and threading while maintaining privacy.
Gift wrap storage
While the decrypted content is stored for display, Hoot also maintains a mapping between:- The gift wrap event ID (encrypted envelope)
- The inner rumor event ID (decrypted message)
- The recipient who received this copy
- Deletion requests: When a sender deletes a message, Hoot can identify which gift wraps to mark as deleted
- Multi-device sync: Different devices may receive different encrypted copies
- Privacy protection: Ensures gift wraps aren’t unnecessarily decrypted multiple times
Multiple accounts
Hoot supports multiple keypairs in the same application. FromCLAUDE.md:49:
AccountManager coordinates key loading, generation, and gift-wrap decryption
When a gift-wrapped event arrives, Hoot tries to decrypt it with all loaded keys. If any key successfully decrypts the message, it’s stored and displayed in the inbox.
This allows you to:
- Check multiple email identities in one app
- Receive messages sent to any of your public keys
- Switch between accounts without losing messages
Each account’s private keys are stored securely using platform-specific key storage (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows).