diff --git a/352.md b/352.md new file mode 100644 index 0000000000..991d9571e9 --- /dev/null +++ b/352.md @@ -0,0 +1,180 @@ +NIP-352 +======= + +Bitcoin Silent Payment Address +------------------------------- + +`draft` `optional` + +## Summary + +A Nostr event for publishing a static Bitcoin Silent Payment address +(`sp1...`) discoverable via social identity. + +## Motivation + +BIP-352 Silent Payments let a sender pay a static address without +address reuse. A parallel effort, Nostr Silent Payments (NSP), defines +a deterministic derivation of an `sp1...` address from any Nostr public +key: a sender computes the recipient's SP address from their `npub` +alone, with no relay query and no action required from the receiver. + +NSP's zero-action property is useful, but it fixes two things that some +receivers will want to control: + +1. **No rotation.** The address is mathematically bound to the Nostr + keypair. To change it the receiver must change their Nostr identity. +2. **No opt-out.** Anyone who knows an npub can compute the payment + address. The receiver cannot separate payment identity from social + identity, nor prevent the mapping from being computed. + +This NIP defines the receiver-controlled announced address layer: +the receiver signs and publishes their `sp1...` address as a Nostr +event; senders query for it before paying. The derivation of the address +from any particular key is out of scope — the protocol cares only about +what is announced, not how it was computed. + +NIP-352 and NSP are complementary. NSP is a reasonable fallback when no +kind:30352 event has been published. When a kind:30352 event exists, +senders SHOULD prefer it, because it represents the receiver's explicit +and current choice. + +## Event kind + +**kind: 30352** + +Events in the `30000–39999` range are *addressable*: for each +combination of `(kind, pubkey, d-tag value)`, relays keep only the +latest event. This gives each `(pubkey, network)` pair its own +independently replaceable slot. + +`30352 = 30000 + 352 (BIP-352)`. + +## Tags + +| Tag | Value | Required | Description | +|-----|-------|----------|-------------| +| `d` | `"mainnet"` \| `"signet"` \| `"testnet"` | yes | Network. Forms the per-pubkey replaceable key together with `kind`. | +| `sp` | `sp1...` address | yes | The BIP-352 static payment address. | +| `payment_pubkey` | 33-byte compressed pubkey (hex) | no | The public key from which `sp` is derived. Allows receivers to prove derivation provenance without revealing the private key. Senders do not need this tag to pay. | + +Content: empty string or a free-form human-readable note (ignored by +protocol implementations). + +## Example + +```json +{ + "kind": 30352, + "pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "content": "", + "tags": [ + ["d", "mainnet"], + ["sp", "sp1qqgmccn46xdv3dfts7e7y9k3m5ln7xa4rqe4rqdvnn9vp6kfzr6lqzgq..."], + ["payment_pubkey", "02a1b2c3..."] + ], + "created_at": 1750000000, + "id": "...", + "sig": "..." +} +``` + +## Discovery + +To find a payment address for a given npub: + +```json +{"kinds": [30352], "authors": [""], "#d": ["mainnet"]} +``` + +Take the event with the highest `created_at`. Relays SHOULD return only +the latest, but clients MUST handle duplicates from non-conforming +relays. Read the `sp` tag value. Pay using any BIP-352-compatible wallet. + +## Rotation + +Publish a new kind:30352 event with the same `d` tag value. The new +event replaces the old one at compliant relays. Senders SHOULD re-fetch +before initiating a payment rather than relying on cached addresses. + +## Verification (optional) + +If `payment_pubkey` is present, a client MAY verify that the `sp` +address encodes the correct scan and spend keys per BIP-352. This is +purely informational — a sender does not need to perform this check to +construct a valid payment. + +## Rationale + +**Why kind:30352 and not kind:10352?** +Events in `10000–19999` are replaceable per `(kind, pubkey)` — the +`d`-tag value is not part of the relay's deduplication key. A signet +publication would overwrite the mainnet address. The addressable range +`30000–39999` uses `(kind, pubkey, d)` as the key, so mainnet and +signet live in independent slots. + +**Why not kind:0?** +Kind:0 is a single mutable blob per pubkey. Embedding an SP address +there conflates two orthogonal concerns: social profile and payment +identity. A dedicated kind allows independent rotation (publishing a new +kind:30352 does not touch the profile), supports per-network addresses +via the `d` tag, and is simpler to query, cache, and index. + +**Why is derivation out of scope?** +The sender needs only the `sp1...` string to construct a BIP-352 +payment. Whether the receiver derived it from their Nostr key, a +hardware wallet, or an entirely separate keypair is invisible on-chain +and irrelevant to the sender. Mandating a derivation scheme would +constrain receiver key management without any protocol benefit. + +**Why is `payment_pubkey` optional?** +Most receivers will omit it. It is useful when a receiver wants to let +clients verify that `sp` was computed from a specific key they control — +for example, to prove that a deterministically derived address is +consistent with a published scheme. It is not a protocol requirement for +payment; it is a provenance hint for clients that want it. + +## Implementation notes + +*This section is non-normative.* + +Receivers control how they derive the keypair behind their published +`sp` address. Three common approaches: + +- **From the social key** — derive the SP keypair from the Nostr nsec + directly. Simple; single key to manage. Trade-off: the link between + Nostr identity and payment identity is permanent and computable by + anyone who has the nsec. + +- **Deterministic sub-key** — derive a separate payment key from the + nsec via a tagged hash (e.g. `tagged_hash("nostr-payment/v1", nsec)`). + Recoverable from the nsec alone; the payment address is not computable + from the npub. Rotating means incrementing the index and republishing. + +- **Independent keypair** — generate a dedicated keypair with no + relation to the Nostr key. Maximum isolation. Requires a separate + backup; losing it means losing access to received UTXOs. + +Clients that want to pay an npub that has not published a kind:30352 +event may fall back to NSP derivation (computing the address from the +npub directly per the NSP spec), but SHOULD make this fallback visible +to the user: the NSP-derived address ignores any rotation the receiver +may have performed and cannot be opted out of by the receiver. + +## Related NIPs + +- [NIP-01](01.md): Defines addressable events (`30000–39999`) +- [NIP-19](19.md): bech32 encoding used for `sp1...` addresses and npubs +- [NIP-65](65.md): Analogous pattern — per-pubkey metadata as an + addressable event +- [NSP (PR #2355)](https://github.com/nostr-protocol/nips/pull/2355): + Nostr Silent Payments — deterministic derivation of an `sp1...` + address from any `npub`, requiring no receiver action. NIP-352 is the + receiver-controlled announcement layer intended to work alongside NSP: + a published kind:30352 event takes precedence; NSP derivation is the + fallback. + +## Reference implementations + +- [Nostru](https://github.com/i2dor/nostru) — Chrome extension; + publishes and discovers kind:30352 events.