Private lightning zaps are a way to send a zap while not revealing the zap author. Only the receiver of the zap can see who sent the zap, and may include an optional private message.
A private zap request is used to send a zap to a user but only revealing the sender's identity to the receiver.
An anon tag is added to the zap request event with the encrypted private zap request event.
The private zap event is encrypted using NIP-04 between the zap request key and the recipient's pubkey. The zap request key is the ephemeral key used to sign the zap request event.
The encrypted private zap request event is then added to the zap request event as the anon tag bech32 encoded with the hrp of pzap1 and the iv values of the encryption are added with an underscore followed by the iv being bech32 encoded wit the hrp of iv.
Example Private Zap Event:
{
"id": "9bf0e1d812e10faa5fd3d2560637f8e99fcbfff478583d2c835754d791acfda5",
"pubkey": "385c3a6ec0b9d57a4330dbd6284989be5bd00e41c535f9ca39b6ae7c521b81cd",
"created_at": 1708467377,
"kind": 9733,
"tags": [
[
"p",
"aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4"
]
],
"content": "Private Zap message!",
"sig": "48cc725483f41207e83c48f3d01a4e5d341bedcf556e158c19b9faac42bca30e92113049268522cd5052ab3c69850c5df7e2b4fb40c72ce770996edee5a57c8d"
}
Example Private Zap Request Event:
{
"id": "4ef9df0a6c7dd8b761145acc7055ae077df716bd8c374496d1f598c5b63bcd7a",
"pubkey": "79d4773fded68a3ea9a30f13e651ff83e150957dacb0c2f6038883d837e1b17b",
"created_at": 1708466564,
"kind": 9734,
"tags": [
[
"p",
"aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4"
],
[
"relays",
"wss://relay.damus.io"
],
[
"anon",
"pzap1n0pkup9fxc9w3yd2tvfr03shffrapfz8rtzu9kkq6v222jw5rgtp9myyh378gdtwptpnls8f0rv0v2dyapgt7sssu4263puepgshsj9g4u9y5lvfv9fsujlgvywsuejvftlfzcanu5fmnf2a3grlelwe8v0z4mdkyhr9mddxpswtvp7mtlc4acdys7740t0x5ej36qs5amfzwz5dpwlaf4gsl69lzhqdgc3hgt62xw4y8384a6zvsnf96l3ardkd2vkk6cm77p6v7ul3gwgjr7tra7uzpkvf4hncxp5qd75h6cdadf6n2d7edhc3dyyy7qpdka2mgqhvckhzhd2gcaux34jyw6qfk3nxhaaqs6pqkuy6z34wu2p2fvqqvg55eyqlrndjlgekm7xu08lqc3g0nje59uqu0adqerv2puypez3eck9xzupg4vxyfclk37qfqxra8nt4tk9ydc2tzhpnl4wpf7jf2nrkchknfnfgmezfyqe074dexe5mkxgw67j7zn8s24tae8tml747qnq0edw5jxsx6xfc4qhshf3man0s5duw6wm63ue8fese8c7hanqzphjna3g0ee4jgpwceqzk9jgrvf9rnkt89tkvh75qm65nvtqpud30vecwlqzdlu9fhcaj7jv89gpy32y2k828vsj7x8hmlq55rleeq23e062apenymv96tkvltv266ww6kly2q2t7k6z_iv189a0s9afn7ehz4gpeanueh56cv6t79qk"
]
],
"content": "",
"sig": "95984f4403a4f414436270584a2ea1e3b83c988a0794ed8438f7d214714de3d982edf5eaf494362333ee07b2ce49c64c1d1206ec3914e9c7d7d4bf958d8bbfad"
}Ephemeral keys can be generated deterministically by generating a private key like so:
func generate_private_keypair(our_privkey: Privkey, id: NoteId, created_at: UInt32) -> FullKeypair? {
let to_hash = our_privkey.hex() + id.hex() + String(created_at)
guard let dat = to_hash.data(using: .utf8) else {
return nil
}
let privkey_bytes = sha256(dat)
let privkey = Privkey(privkey_bytes)
guard let pubkey = privkey_to_pubkey(privkey: privkey) else { return nil }
return FullKeypair(pubkey: pubkey, privkey: privkey)
}The private key is generated using the sha256 of the following data concatenated together:
- our_privkey: is the user sending the notes private key
- id: the target note that you are zapping's note id
- created_at: the target note's created_at as a string
This allows you to decode private zaps that you have sent yourself by attempting to generate a matching pubkey from public data on the target note
Note that this will not work on the web, since NIP-07 does not support hashing the private key into other data.