Skip to content

NIP-BC: Onchain Zaps (kind 8333)#2332

Open
alexgleason wants to merge 5 commits into
nostr-protocol:masterfrom
alexgleason:onchain-zaps
Open

NIP-BC: Onchain Zaps (kind 8333)#2332
alexgleason wants to merge 5 commits into
nostr-protocol:masterfrom
alexgleason:onchain-zaps

Conversation

@alexgleason
Copy link
Copy Markdown
Member

@barrydeen
Copy link
Copy Markdown

NACK - I think this is gonna lead to just more p2tr dust utxos and confused users who can't move coins when we exit this low fee environment. Shouldn't be encouraging clients to implement this imo

@alexgleason
Copy link
Copy Markdown
Member Author

ohhh now you don't like utxos??

@derekross
Copy link
Copy Markdown

NACK - I think this is gonna lead to just more p2tr dust utxos and confused users who can't move coins when we exit this low fee environment. Shouldn't be encouraging clients to implement this imo

The more that I've thought about this over the last few days, I agree with this take. Right now, this works based on the current price and current fee market. In the near future, this may not work if the fiat price increases and/or transaction fees increase. I like the proposal due to Zaps being hard to implement in a UX friendly manner that doesn't add centralization. However, I'm not certain if this is the best path forward.

@vitorpamplona
Copy link
Copy Markdown
Collaborator

vitorpamplona commented May 8, 2026

lol, I was just thinking of re-making Bitcoin Core's Blockchain structure in Kotlin so that we can have the full chain on the phone to validate OTS records without depending on a block explorer... Now I have another idea :)

@alexgleason
Copy link
Copy Markdown
Member Author

NACK - I think this is gonna lead to just more p2tr dust utxos and confused users who can't move coins when we exit this low fee environment. Shouldn't be encouraging clients to implement this imo

The more that I've thought about this over the last few days, I agree with this take. Right now, this works based on the current price and current fee market. In the near future, this may not work if the fiat price increases and/or transaction fees increase. I like the proposal due to Zaps being hard to implement in a UX friendly manner that doesn't add centralization. However, I'm not certain if this is the best path forward.

If you are not zapping $5, you don't understand this proposal. Zap $5. Stop being cheap. Would you drop 2 pennies into a guitar case? The whole mindset needs to shift.

@alexgleason
Copy link
Copy Markdown
Member Author

The idea that if you got 100,000 likes it could convert into money for you is an idea from the dream that Nostr could actually replace Twitter. We're past that point. Nobody can actually survive off 21 sat zaps. It's not even worth the fee of converting Lightning into "real bitcoin"

@alexgleason
Copy link
Copy Markdown
Member Author

Also, I suspect that people will be against this for ideological reasons when they have not even tried it. They think it can't work even though it's working right now.

@vitorpamplona
Copy link
Copy Markdown
Collaborator

Good thing that on nostr no one can stop anything

@jb55
Copy link
Copy Markdown
Contributor

jb55 commented May 8, 2026

NACK in its current form. this would enable a mass utxo doxxing mechanism for everyone using these. let's do it properly with silent payments

@jb55
Copy link
Copy Markdown
Contributor

jb55 commented May 8, 2026

I actually don't think the spam issue is that big of a deal since fees are low and the market will adapt to lightning or onchain depending on the fee market, but the privacy does concern me as it links utxos to nostr identities and that can be used to track the entire tx history of a person. would be an amazing resource for chainalytics

@alexgleason
Copy link
Copy Markdown
Member Author

NACK in its current form. this would enable a mass utxo doxxing mechanism for everyone using these. let's do it properly with silent payments

This doesn't make sense to me. Zaps are already public. What are you worried about?

@barrydeen
Copy link
Copy Markdown

NACK in its current form. this would enable a mass utxo doxxing mechanism for everyone using these. let's do it properly with silent payments

This doesn't make sense to me. Zaps are already public. What are you worried about?

We don't know where the coins flow after the zap takes place, they don't consolidate with other utxos or show users exchange deposit address the way chain zaps will eventually flow

@fiatjaf
Copy link
Copy Markdown
Member

fiatjaf commented May 8, 2026

This is incredibly short-sighted, but I think people should do it, because Lightning is stupid and miners have to be paid.

Also if we manage to bloat the UTXO set enough that could be promotion for Nostr, some people might even do a soft-fork to filter onchain zaps from Bitcoin.

@vitorpamplona
Copy link
Copy Markdown
Collaborator

vitorpamplona commented May 8, 2026

Gotta love Claude:

Propose adding two optional tags to kind:8333:

["block", "<block-hash-hex>", "<height>"]
["proof", "<raw-tx-hex>", "<merkle-proof-hex>"]

Then a client with only the bitcoin headers chain (75 MB) can:

  • Locate the header by block-hash (or by height).
  • Hash the raw-tx-hex → txid; check it matches the i-tag txid.
  • Walk the merkle proof up to the header's merkleRoot.
  • Parse outputs from the raw tx, match scriptPubKey, sum.
  • Confirmations = current tip height − block height + 1.

Per-event payload cost: ~1 KB

We only need block headers! Nothing else from the chain is touched — no transactions, no UTXOs, no scripts, no witness data, no mempool. That is a ~75 MB download for the entire chain, 1–10 minutes wall-clock, ~2 s CPU, ~72 MB on disk directly from the Bitcoin network.

Unless you expect more than 1M on-chain zap events on a session. At that time, the cost of downloading the 1-2GB of compact chain filters (Neutrino-style) is better than downloading 1M heavier onchain zap events.

@alexgleason
Copy link
Copy Markdown
Member Author

@vitorpamplona added block and proof tags to the NIP

@jb55
Copy link
Copy Markdown
Contributor

jb55 commented May 8, 2026

NACK in its current form. this would enable a mass utxo doxxing mechanism for everyone using these. let's do it properly with silent payments

This doesn't make sense to me. Zaps are already public. What are you worried about?

there is a huge difference. linking onchain zaps to utxos can leak someones entire bitcoin tx history. zaps reveal a single payment and nothing else (and its not even a proof, so its deniable)

@alexgleason
Copy link
Copy Markdown
Member Author

Okay, I understand.

But the problem with silent payments is that you can lose money on relays, which is exactly what I was trying to avoid. My hope for this spec is that it can provide a path that is extremely frictionless and guarantees access to funds. We can only do that if your key is 1:1 Nostr to Taproot. All your payment data exists on the blockchain.

The way I imagine silent payments would work is that you'd tweak the recipient's pubkey and then send them an encrypted message with the tweak. This is already very similar to how nutzaps work, a major problem of which is that if you can't find the event on relays you can't get the money. I prioritize deliverability and access to funds in this design over privacy.

Silent payments could still be supported, but I don't think it should be the default path for the majority of users. It just needs to be clear to users that transactions are public, probably by surfacing onchain data in Nostr clients and in feeds, and letting them comment on it with NIP-73.

@jb55
Copy link
Copy Markdown
Contributor

jb55 commented May 8, 2026

not sure what you mean you can lose the money on relays. with silent payments you can just put a silent payment address in your profile. we would then just need a mechanism for a bitcoin node to send an onchain zap signed by your key that verifies that the payment is correct, but it doesn't need to doxx any utxos.

we could have it send a private and public parts of the zap, where private shows more detailed information. the public part of the zap could have blinded amounts so its not as easy to trace onchain (or could even be optional)

@jb55
Copy link
Copy Markdown
Contributor

jb55 commented May 8, 2026

another thing we should consider is zero-conf onchain zaps, like "tx pending". so you would have immediate feedback in apps. bitcoin core nodes have a walletnotify system for handling 0 and 1-conf bitcoin txs, so it would be perfect for this.

i already do private onchain zap notifications for all incoming txs using giftwrapped kind1s. standardizing this would be great.

@alexgleason
Copy link
Copy Markdown
Member Author

Okay, I didn't really understand how silent payments work. That's mind blowing. 🤯 I'm still grokking it, but isn't it a downside that the client/wallet has to do a lot of work to figure out what your balance is? Chatting with Claude, you have to scan every block, so you can't just rely on an API like mempool.space. You need to either be running a full node or rely on a trusted server.

@alexgleason
Copy link
Copy Markdown
Member Author

I just released Ditto Extension on the Chrome Webstore that has support for window.nostr.signPsbt(): https://chromewebstore.google.com/detail/ditto-extension/fbiegkepanmjielbemkhieckmlckiagi

image image image

It's really good. The screenshots are Halloween themed because it uses your Ditto theme if you have one. It has a built-in onchain Bitcoin wallet.

The signPsbt method works with tweaks, so it would be forwards-compatible with silent payments as well as gift-wrapped tweaks. I feel good about it.

@stl1988
Copy link
Copy Markdown
Contributor

stl1988 commented May 16, 2026

I actually don't think the spam issue is that big of a deal since fees are low and the market will adapt to lightning or onchain depending on the fee market, but the privacy does concern me as it links utxos to nostr identities and that can be used to track the entire tx history of a person. would be an amazing resource for chainalytics

Exactly this!

@CyberDexter
Copy link
Copy Markdown

The idea that if you got 100,000 likes it could convert into money for you is an idea from the dream that Nostr could actually replace Twitter. We're past that point. Nobody can actually survive off 21 sat zaps. It's not even worth the fee of converting Lightning into "real bitcoin"

They could always try and get a job

@vitorpamplona
Copy link
Copy Markdown
Collaborator

vitorpamplona commented May 18, 2026

I think this works for SP generation so that keys don't need to declare their address. I just don't know exactly what to put into the ZapEvent itself, since it would reveal all the protections that Silent Payments added.

Basically, the sender can automatically compute the SP of a receiver's public key and lock the funds into one of the UTXOs. At the same time, nobody else can pull all UTXOs of a pubkey.

The address generation, end to end

Inputs

  • npub_pubkey: 32-byte x-only secp256k1 point (BIP-340 convention, implicit even-y)
  • npub_privkey: the corresponding 32-byte scalar (recipient only)

Sender side (anyone with the npub)

P_base  = lift_x(npub_pubkey)                                 // 33-byte point, even-y
tweak   = int(tagged_hash("nip-XX/sp-scan", npub_pubkey)) mod n
B_spend = P_base                                              // 1:1 with the npub
B_scan  = P_base + tweak · G

Optional override: if the recipient has published a kind 10336 event carrying a hardened B_scan_hardened, use that instead of the derived B_scan. Senders that always paid the unhardened address before will keep matching, because the recipient's hardened wallet also runs detection against the unhardened b_scan.

Address encoding (BIP-352 standard)

payload    = version(0x00) || compress(B_scan) || compress(B_spend)   // 1 + 33 + 33 = 67 bytes
sp_address = bech32m("sp", payload)                                   // → "sp1q…"

Recipient side

b_spend = npub_privkey                                                // = identity privkey
b_scan  = (npub_privkey + tweak) mod n                                // unhardened
   or
b_scan  = int(tagged_hash("nip-XX/sp-scan-hardened", npub_privkey))   // hardened (override)

Parity / lift_x note. The npub is x-only; SP math is on full points. Convention: always lift_x with even-y. The per-output key P_k = B_spend + t_k · G is the internal taproot key — the output script uses its x-only form (P_k's x-coordinate as the taproot output key, no script path). Standard BIP-341 normalization applies.

That's the whole address spec: one tagged-hash tweak, one point addition, one bech32m encoding. No new event kinds required for the default case; one optional replaceable event for the safe-delegation override.


Privacy features

  • On-chain unlinkability. Every received output is a fresh-looking taproot key. A chain analyst with the npub can compute the SP address and still cannot identify any output as belonging to it (CDH-hard without b_scan). The recipient's income stream is invisible from chain alone.
  • No sender-recipient interaction. Recipient can be offline indefinitely; sender pays using only the npub. No address handshake, no LNURL callback, no relay roundtrip required to pay.
  • Address is publicly safe to share. Publishing the SP address (or letting it be derived from the npub) leaks nothing on-chain — it's just two public points, and observing them doesn't break CDH.
  • Light-client scanning preserves recipient privacy. Tweak-index servers serve generic per-block public data computed from chain only; the recipient runs the final match locally with b_scan. The indexer never sees the scan key or learns which outputs are the recipient's.
  • Hint events (gift-wrapped) decouple discovery from public linkage. The on-nostr receipt for fast detection is sealed with NIP-17, so relay observers see neither the sender, the recipient, nor the txid.

Privacy limitations

  • The address is a public 1:1 function of the npub. Anyone who knows your npub can compute your SP address — and therefore the social graph "this npub has an on-chain payment surface" is fully public. There is no unlinkable subaddress per payer; the trade for 1:1 is loss of identity-vs-address separation. (BIP-352 labels could provide per-payer subaddresses, but using them means each subaddress needs its own out-of-band publication, breaking the 1:1.)
  • The unhardened scheme makes scan delegation unsafe. b_scan minus the public tweak equals npub_privkey. Any wallet shipping this MUST refuse to export the unhardened scan key. Safe delegation requires the recipient to publish a hardened override and hand out that b_scan_hardened — a manual opt-in step users will mostly skip.
  • Public hint events would destroy the on-chain privacy. Gift-wrapping is not optional. If a client implementation defaults to public ["p", recipient_npub]-tagged hint events, anyone querying relays can reconstruct the full receipt graph from txids in those events. This is the single biggest implementation footgun in the design.
  • Sender always learns one output. Whoever made a payment knows exactly which output they created — including its key, amount, and txid. Standard for any payment system; mentioned for completeness. They cannot extrapolate to other payments the same recipient received.
  • Tweak-index queries leak metadata at the IP layer. Even though the server doesn't see b_scan, it sees "this IP is requesting block tweaks." Mitigations are network-level (Tor, mixing, batching) and outside the spec.
  • On-chain amounts are public. Bitcoin baseline. Once a tx is located (by anyone who learns the txid through whatever channel), the amount is visible. SP hides which tx, not what was in it.
  • Timing correlation across nostr and chain. Even with gift-wrapped hints, an adversary watching both relays and the mempool can correlate "encrypted nostr event T+Δs after tx confirms" to link payments to recipients statistically. Mitigations are batching/delays/cover traffic, with the usual cost.
  • Override rotation is cache-sensitive. Republishing kind 10336 with a new B_scan_hardened creates a window where senders see different versions; require valid_from plus an overlap period during which both keys remain detectable. Otherwise in-flight payments can land on a key the recipient no longer scans for.

One-line summary

A nostr npub becomes an sp1… address via one tagged-hash tweak — sender-derivable, recipient-private, on-chain unlinkable, and nostr-unlinkable as long as hint events are gift-wrapped. The two structural costs are: (1) the npub→address mapping is public, so the address can't double as a private identity, and (2) the unhardened scan key is identity-equivalent, so scan delegation requires the opt-in hardened override.

A single Bitcoin transaction paying N recipients now produces a single
kind 8333 event listing every recipient under its own p tag. The amount
tag carries the total sats paid to all listed recipients (excluding the
sender's change). Single-recipient events remain the degenerate case.

Per-recipient amounts are not encoded in the event; clients that need
them recompute them from the on-chain transaction by matching each
recipient's derived Taproot address against the tx outputs. The
deduplication key simplifies from (txid, target) to txid.
@alexgleason
Copy link
Copy Markdown
Member Author

I updated kind 8333 to optionally include multiple p-tags. This is for a "make it rain" feature where a single transaction has outputs for multiple Nostr users.

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 19, 2026

NACK if it's p2tr *, ACK if it's ** the nsec deriving up to a p2pkh or p2wpkh address without vendor lock-in.

ETA:
*exclusively
**optionally

@alexgleason
Copy link
Copy Markdown
Member Author

@TheButterZone people have already gotten it working in Sparrow and it should work in recent versions of Electrum. It is p2tr but wallets support it.

Addresses ambiguities raised by @vitorpamplona in nostr-protocol#2332:

- proof requires block (MUST)
- block-height: stringified non-negative integer <= 2^31-1, no leading zeros
- block-hash-hex and txid in display order; merkle-proof hashes in
  internal byte order
- leaf is txid = dsha256(strip_witness(rawTx))
- merkle-proof-hex is N 33-byte steps: 1 direction byte + 32-byte sibling
- direction 0x00 = sibling right, 0x01 = sibling left, other values reject
- N MAY be 0 (1-tx block): empty proof, verifier checks txid == merkleRoot
- N MUST NOT exceed 32; length MUST be a multiple of 33
- odd-level duplication: producer emits direction=0x00, sibling=cur
- include verification algorithm pseudocode
- sender MAY publish twice (pre-confirm without tags, post-confirm with);
  verifiers dedupe by (txid, recipient-set, target) and prefer the
  variant with a valid SPV proof
- failed proof falls back to remote verification, not a hard reject
@alexgleason
Copy link
Copy Markdown
Member Author

@vitorpamplona Updated

@TheButterZone
Copy link
Copy Markdown

Optional Compatibility Layer for Legacy Bitcoin Addresses (Non-normative)

Thanks for the work on this PR — the Taproot mapping is clean and well-scoped.

While reviewing the use of x-only secp256k1 keys (BIP340-style), I ran into a practical interoperability edge case that may be worth documenting as an optional, non-normative compatibility note.

Context

Nostr public keys (npub) are 32-byte x-only secp256k1 values.
However, legacy Bitcoin address formats:

  • P2PKH (Base58Check)
  • P2WPKH (SegWit v0)

require a compressed secp256k1 public key, which includes a parity byte:

0x02 = even y
0x03 = odd y

Since x-only keys omit parity, a deterministic rule is required if legacy address display is desired from only an npub.

Proposed Compatibility Rule (Deterministic)

If implementers wish to derive legacy Bitcoin addresses from an x-only Nostr pubkey:

The x-only pubkey SHALL be interpreted as a compressed secp256k1 public key by prefixing it with 0x02 (even-y assumption).

This yields a deterministic mapping:

compressed_pubkey = 0x02 || xonly_pubkey

Optional Wallet Interoperability (Private Key Export)

Nostr private keys are not defined in Bitcoin wallet formats. However, for interoperability with existing Bitcoin software:

Nostr clients MAY optionally expose Bitcoin compatibility by deriving WIF from nsec for import into existing Bitcoin wallets.

This is strictly an implementation convenience and is not part of the Nostr protocol or key format specification.

Why this design choice (anticipated objections)

Objection 1: “Why force even-y? Isn’t that arbitrary?”

Yes — but parity is not recoverable from x-only keys, so any legacy mapping must choose a convention.

We choose 0x02 because:

  • it is deterministic and globally consistent
  • it avoids branching logic or ambiguity
  • it aligns with a simple “default compressed form” assumption
  • it prevents wallet fragmentation across implementations

Importantly:

This does NOT claim to recover the original secp256k1 point — it only defines a deterministic display/compatibility encoding.

Objection 2: “Why not use both 02 and 03 and pick one?”

Using both would produce:

  • two valid P2PKH addresses
  • two valid P2WPKH addresses
  • inconsistent UX across implementations
  • inability to define a canonical output

This would defeat determinism, which is required for interoperable wallet behavior.

Objection 3: “Why include legacy address derivation at all?”

This is strictly optional and not part of Taproot behavior.

It is included only because:

  • some existing wallets / tooling still rely on P2PKH or P2WPKH
  • users may expect “Bitcoin address equivalents” of their Nostr identity
  • migration tooling benefits from deterministic mapping

If not needed, implementations MAY ignore this entirely and use only Taproot (P2TR).

Full Reference Implementation (Python)

import hashlib
import base58

from Crypto.Hash import RIPEMD160
from bech32 import bech32_encode, convertbits


# -----------------------------
# HASH160 (Bitcoin standard)
# -----------------------------

def hash160(data: bytes) -> bytes:
    sha = hashlib.sha256(data).digest()
    ripemd = RIPEMD160.new()
    ripemd.update(sha)
    return ripemd.digest()


# -----------------------------
# x-only -> compressed pubkey
# -----------------------------

def xonly_to_compressed_pubkey(xonly_pubkey: bytes) -> bytes:
    """
    Deterministic compatibility rule:

    Prefix x-only secp256k1 pubkey with 0x02 (even-y assumption)
    to produce a valid compressed ECDSA public key.

    This is a convention ONLY and not a reconstruction of the
    original elliptic curve point.
    """

    if len(xonly_pubkey) != 32:
        raise ValueError("Invalid x-only pubkey length")

    return b"\x02" + xonly_pubkey


# -----------------------------
# P2PKH (legacy)
# -----------------------------

def pubkey_to_p2pkh(pubkey: bytes) -> str:
    h160 = hash160(pubkey)

    payload = b"\x00" + h160  # mainnet version byte

    checksum = hashlib.sha256(
        hashlib.sha256(payload).digest()
    ).digest()[:4]

    return base58.b58encode(payload + checksum).decode()


# -----------------------------
# P2WPKH (SegWit v0)
# -----------------------------

def pubkey_to_p2wpkh(pubkey: bytes) -> str:
    h160 = hash160(pubkey)

    data = [0] + convertbits(h160, 8, 5)

    return bech32_encode("bc", data)


# -----------------------------
# Compatibility API
# -----------------------------

def nostr_xonly_to_legacy_bitcoin_addresses(xonly_pubkey: bytes) -> dict:
    """
    Optional compatibility layer.

    Not part of Taproot or core Nostr semantics.

    Provides deterministic legacy Bitcoin address derivation
    from x-only secp256k1 pubkeys.
    """

    compressed_pubkey = xonly_to_compressed_pubkey(xonly_pubkey)

    return {
        "compressed_pubkey_hex": compressed_pubkey.hex(),
        "p2pkh": pubkey_to_p2pkh(compressed_pubkey),
        "p2wpkh": pubkey_to_p2wpkh(compressed_pubkey),
    }

Relationship to Taproot (important scope clarification)

This does not modify Taproot behavior.

  • Taproot (P2TR) remains canonical for x-only keys
  • This compatibility layer is purely for legacy Bitcoin interoperability
  • It does not affect key generation, signing, or address validity

Summary

This proposal adds:

  • deterministic legacy address derivation from x-only keys
  • no changes to core Nostr or Taproot semantics
  • a single, explicit convention (0x02) to avoid ambiguity
  • optionality for implementers

Response to “Out of scope / should be omitted”

A likely objection is that legacy Bitcoin address derivation should not be included in a Taproot-focused or Nostr-focused specification.

However, this note does not introduce new functionality or expand protocol semantics. It only formalizes an existing ambiguity in implementation space.

Key point

Given an x-only secp256k1 public key, any system that attempts to derive a legacy Bitcoin address must choose one of:

  • 0x02 || x (even-y assumption)
  • 0x03 || x (odd-y assumption)

This choice already exists implicitly in any implementation that supports such conversion. Without standardization, different clients will produce different addresses for the same npub.

Why omission does not remove the problem

If this note is omitted:

  • implementations will still perform compression
  • they will simply do so inconsistently
  • resulting in non-interoperable legacy address outputs

Thus, omission does not avoid the behavior — it only prevents it from being deterministic.

Why inclusion is safe

This proposal:

  • does NOT modify Taproot behavior
  • does NOT modify Nostr key semantics
  • does NOT introduce new cryptographic assumptions
  • only fixes a deterministic rule for an unavoidable encoding step

Design principle

This follows the same principle used in other standards:

When a lossy representation is unavoidable, define a canonical default rather than leaving it implementation-defined.

[With help or help? from ChatGPT, including a bunch of code iterations & runs on https://playcode.io/python-playground - since I can barely code & read console output... I beg forgiveness/steelman/for a pointer anywhere else I should post this. Thanks in advance.]

@dergigi
Copy link
Copy Markdown

dergigi commented May 20, 2026

Zaps are already public. What are you worried about?

Let me paint you a picture:

Let’s say I’m a criminal, and I "on-chain zap" everyone on nostr. Some of my targets will inevitably move their UTXOs to cold storage, potentially combining what I’ve sent (and what I’m now tracking) with their main stash.

I have a script running that notifies me of this (only if it’s above a certain amount, of course). A couple of days later I get such an alert. Jackpot. Generational wealth. I rub my hands as I browse nostr for the latest posts of my unsuspecting victim. Between memes and casual shitposts I find a link to a concert as well as an image they took on a stroll. There’s a mountain range in the background. I paste the image into a geolocation engine. It matches the concert location almost perfectly. I scroll further down and find multiple selfies and a photo of their dog.

I now know where they live, what they look like, what their dog looks like, and where they usually go to take their dog on a walk.


In short: a small zap could lead an attacker to a very large bounty. This is not an issue with regular zaps.

@dergigi
Copy link
Copy Markdown

dergigi commented May 20, 2026

the public part of the zap could have blinded amounts so its not as easy to trace onchain (or could even be optional)

Yes, any sane proposal would have to use blinded or otherwise obfuscated amounts, destroying a large part of what makes zaps interesting.

Zaps and numerology go hand-in-hand. 21 sats here, 69,420 sats there, palindrome zaps, etc. We can’t do any of that if we hit the chain directly because broadcasting the exact amount would make it trivial for an attacker to identify the actual transaction.

@vitorpamplona
Copy link
Copy Markdown
Collaborator

I just added a warning to inform users who are trying to drain the wallet not to mix their nostr funds with their cold wallets and always fund or drain from exchanges. That fixes your concern.

@dergigi
Copy link
Copy Markdown

dergigi commented May 20, 2026

NACK for reasons articulated at length here.

Lots of footguns, lots of negative long-term implications. The negative effects outweigh any supposed benefit by a mile.

@dergigi
Copy link
Copy Markdown

dergigi commented May 20, 2026

I just added a warning to inform users who are trying to drain the wallet not to mix their nostr funds with their cold wallets and always fund or drain from exchanges. That fixes your concern.

Warning the users doesn't magically "fix" things. Also:

warning the users properly (explaining the risk properly) is borderline impossible. You’d have to warn them about the past. You’d have to warn them about the present. You’d have to warn them about the future. You’d have to warn them that any potential attacker has undeniable, cryptographic proof that they, the target, are in possession of sats. You’d have to warn them that they can’t plausibly deny this fact because of the non-repudiation of digital signatures.

I’ve said it before, and I’ll say it again: plausible deniability matters.

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 21, 2026

Zaps are already public. What are you worried about?

Let me paint you a picture:

Let’s say I’m a criminal, and I "on-chain zap" everyone on nostr. Some of my targets will inevitably move their UTXOs to cold storage, potentially combining what I’ve sent (and what I’m now tracking) with their main stash.

I have a script running that notifies me of this (only if it’s above a certain amount, of course). A couple of days later I get such an alert. Jackpot. Generational wealth. I rub my hands as I browse nostr for the latest posts of my unsuspecting victim. Between memes and casual shitposts I find a link to a concert as well as an image they took on a stroll. There’s a mountain range in the background. I paste the image into a geolocation engine. It matches the concert location almost perfectly. I scroll further down and find multiple selfies and a photo of their dog.

I now know where they live, what they look like, what their dog looks like, and where they usually go to take their dog on a walk.

In short: a small zap could lead an attacker to a very large bounty. This is not an issue with regular zaps.

That's why if you're intelligent enough to not need 24/7 guardianship/caregivers, you will dedicate one cold storage address for receiving all your coins you ever received at a public address that was associated with your identity (whether actual or same-pseudonym). That means all the Zap sats go there, all the p2pkh & p2wpkh tipping/donation address coins also go there, and then that cold storage address either already was separate from every other address by keeping it as a paper wallet or 1-private-key-only wallet file or at a minimum, frozen & labeled as cold storage within your main wallet.

If you have a change output (I personally try to avoid spending a key until 100% of it goes to receiver with no change), it goes to a new change address that you label & then freeze (and burn/label as burned, the previous cold storage), because that's your new public cold storage. Heck, if you're feeling charitable at burn/address rotation time, you can save yourself the step of immediately creating a new public cold storage by spending the change to charity instead of yourself.

It's self-evident that no implementation (which will always have at least one thing to warn about), will ever be enough for paternalists, who inexplicably act like it's possible for people who need 24/7 guardianship/caregivers to use bitcoin, let alone the internet, as safely as possible alone. Time to stop painting anyone else with that infantilization brush.

@dergigi
Copy link
Copy Markdown

dergigi commented May 21, 2026

Part of the argument seems to be "great UX" and "easy," so thank you for making my point for me.

@dergigi
Copy link
Copy Markdown

dergigi commented May 21, 2026

In addition to all of the above I want to repeat a point that was made in a stacker.news discussion:

Reusing a key across use-cases (or even within use-cases because you wanna roll without random) takes immense cryptographic risk, because weaknesses compound across uses. [...]

Don't take my word for it, let's look at what Schneier & co said about exactly this 1 (I recommend reading the whole paper):

The first and most important rule to follow is to limit the scope of each key. A key should typically have only a small number of closely related functions. There is sometimes a temptation to reuse keys for related applications—this should be avoided whenever possible. If there is only one certified key pair, it should be used to sign (and perhaps even derive) other single-use public keys

This is why we have things like key derivation. You know... like BIP-32. Why using BIP-44 or BIP-84 has a hardened path on their specs (the first derivation in the path is m/44' / m/84'). I could go on forever, but I'm getting to a point where I consider removing myself with great distance from nostr vibes, even before we talk about the whole bitcoin-specific privacy chain of concerns this introduces.

Footnotes

  1. Protocol Interactions and the Chosen Protocol Attack, p10

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 21, 2026

Part of the argument seems to be "great UX" and "easy," so thank you for making my point for me.

Nah, I don't tolerate mini-gish-galloping.

You want to fully-spec out and defeat the Bitcoin Software Iron Triangle for both competent users and people who require 24/7 guardianship, Gigi? Please do.

But don't cheat by making 'great UX' and 'easy' separate dimensions, they fall under Usability.

What are the other two dimensions, and how do you prevent any trade-off between the three so that the needs of those requiring 24/7 care will never force competent users to suffer a trade-off in their own sovereignty, usability, or security?

@dtonon
Copy link
Copy Markdown
Contributor

dtonon commented May 21, 2026

This seems a really questionable idea, with a lot of problems and few advantages in addition to the temporary fun factor; I fully agree with @dergigi, who carefully explained the issues in his last article.
I am truly baffled that such brilliant minds are wasting their time on something so trivial and potentially dangerous.
NACK

@dergigi
Copy link
Copy Markdown

dergigi commented May 21, 2026

You want to fully-spec out and defeat the Bitcoin Software Iron Triangle for both competent users and people who require 24/7 guardianship, Gigi?

I don't want to do that.

I want to point out various issues that seem to be either overlooked or downplayed, and hopefully educate some of the newer people who haven't thought deeply about these issues.

In addition to the conceptual problems that I hopefully managed to explain somewhat coherently, there's plenty of cryptographic issues as mentioned above.

I am truly baffled that such brilliant minds are wasting their time on something so trivial and potentially dangerous.

So am I.

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 21, 2026

You want to fully-spec out and defeat the Bitcoin Software Iron Triangle for both competent users and people who require 24/7 guardianship, Gigi?

I don't want to do that.

I want to point out various issues that seem to be either overlooked or downplayed, and hopefully educate some of the newer people who haven't thought deeply about these issues.

In addition to the conceptual problems that I hopefully managed to explain somewhat coherently, there's plenty of cryptographic issues as mentioned above.

I am truly baffled that such brilliant minds are wasting their time on something so trivial and potentially dangerous.

So am I.

"I don't want to do that' is a tacit admission that the Iron Triangle cannot be defeated. You said you wanted to educate newcomers, Gigi, but redirecting people to your blog (which not all may agree is coherent) is just a detour to avoid a live engineering paradox. Let’s actually educate them right here: your stance forces users requiring 24/7 guardianship to rely on 3rd-party solutions. It confirms that Bitcoin's inherent security, usability, & sovereignty trade-offs cannot be designed away.

Your essay simultaneously reads as a critique of on-chain zaps & Bitcoin's base layer itself. You claim zaps are bad because they link identity to money & expose finances forever. But those aren't design flaws of zaps, those are the literal engineering realities of Bitcoin's public ledger.

Pushing users to L2 to escape this isn’t defeating the Iron Triangle. It’s a total surrender of sovereignty & security. To run a truly self-sovereign Lightning node, users face extreme technical complexity & crippling on-chain capital costs just to manage channels. For the average person, & especially for someone requiring 24/7 care, that is impossible.

So what is your actual alternative? Forcing them onto custodial wallets & 3rd-party clearinghouses where they hold nothing but IOUs. Lightning doesn't solve the triangle. It forces a brutal trade-off: you either keep your keys online 24/7 in a highly vulnerable hot-wallet environment, or you hand your security over to a middleman. Stop pretending L2 is a magic wand when it explicitly strips away the very trustlessness that makes Bitcoin valuable in the first place.

You can't build a single software wallet that accommodates someone requiring 24/7 guardianship without introducing 3rd-party trust or guardrails. If you force those same guardrails onto competent users, you destroy their absolute sovereignty.

We must stop pretending we can design away these fundamental trade-offs with clever UX or layers. We must accept them. And we must practice direct, absolutely-concise counter-evangelism to the provably-mentally-competent caregivers of those most at risk, ensuring they know how to protect vulnerable individuals under their care from a system mathematically bound to offer zero safety nets - DON'T LET THEM USE TECHNOLOGY THAT SUPPORTS L1-L∞.

Education can only help the mentally competent. The engineering laws of the triangle remain undefeated.

@dergigi
Copy link
Copy Markdown

dergigi commented May 21, 2026

We must stop pretending we can design away these fundamental trade-offs with clever UX or layers.

Precisely.

I'm not here to pretend that trade-offs don't exist. I am painfully aware of the trade-offs that Lightning, LUD-16 identifiers, NIP-60/61, or npub.cash bring.1 I think they are worth making.

I joined the discussion to point out certain risks and complications that I didn't see discussed, and I wanted to point them out so developers (and users) can make a proper judgement call when it comes to deciding what to implement (and what to use).

I'm not against on-chain transactions, to the contrary. I'm against permanently and irreversibly tying identities to on-chain activity. I think it's a trade-off that isn't worth making. I think it will harm users in a multitude of ways and it has the potential to harm the network as a whole.

But I think I made my point.2

Footnotes

  1. (and if we ever meet and have a coffee or a beer in real life, I'm happy to talk about all sorts of triangles for hours)

  2. I'll do my best to step away from this discussion now. I've said my piece.

@vitorpamplona
Copy link
Copy Markdown
Collaborator

vitorpamplona commented May 21, 2026

I am painfully aware of the trade-offs that Lightning, LUD-16 identifiers, NIP-60/61, or npub.cash bring.1 I think they are worth making.

We did make those tradeoffs. But none of them work very well. It's not that we didn't try. Heck, we made our own NWC just to go around the lightning API shitshow.

I know it's hard to hear when better privacy tech fails to gain traction, but the world isn't fair. I think the trade-offs listed for each technology were grossly underestimated by everyone, and the privacy limitations of each stack, when put in practice, draw the final straw: "not worth doing".

Lately, not even Silent Payments has convinced me that it is worth working with for Zaps.

I remain open to solutions, and I am happy to test crazy ideas anyone can make. But those ideas need to work in practice. Until then, we are stuck in 2014 tech.

@alexgleason
Copy link
Copy Markdown
Member Author

For the first time ever, Bitcon on Nostr actually works.

@Sebastix
Copy link
Copy Markdown
Contributor

I would like to separate money and identity and don't like the idea that a client, without my permission, can derive a bitcoin address from my nostr pubkey. Period.

I think I know the answer, but my first question that comes in mind is "are there any technical solutions to prevent others creating UTXOs tied to that address"?

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 22, 2026

I would like to separate money and identity and don't like the idea that a client, without my permission, can derive a bitcoin address from my nostr pubkey. Period.

I think I know the answer, but my first question that comes in mind is "are there any technical solutions to prevent others creating UTXOs tied to that address"?

There are not, because in Python, anyone can derive a bitcoin address from virtually any data, no client necessary (and in fact this was done in 2023, someone just discovered & Noted) & then create a UTXO tied to that address, period. The only way to "win", is to not play against all human/machine-kind - don't even generate a npub/use Nostr, in the first place.

Like asking if you can put the genie back in the bottle, or undo the laws of cryptography.

@dergigi
Copy link
Copy Markdown

dergigi commented May 26, 2026

anyone can derive a bitcoin address from virtually any data

Of course.

But does that mean that a bitcoin wallet should encourage users to use "bacon bacon bacon bacon..." as their seed phrase? Of course not. These types of seeds are dangerously insecure.

You can also use any string of characters as a password, but that doesn't mean that we should build software that auto-suggests hunter2 as the password for every user, or allow weak passwords like 123456.

Reusing cryptographic keys across purposes goes against all the best practices we know, not only for conceptual reasons, but also because it weakens the cryptography of the keys and opens up a multitude of attack surfaces and other issues. To quote Bruce Schneier et al. once more: "this should be avoided whenever possible"

The question at hand is not "is this possible?"

The question at hand is: should this be a NIP?

I think the only sensible answer to that question is a resounding NO.

@dergigi
Copy link
Copy Markdown

dergigi commented May 26, 2026

Allow me to make one more comment: if this becomes a NIP or some other form of de-facto standard (because big clients like Amethyst decide to implement it, or even more dangerously: make it some kind of default) one of the side-effects might be that nostr devs are "forced" to deal with the intricacies of bitcoin wallet development.

Developing a secure bitcoin wallet is hard. Very hard.

I've watched the discourse about on-chain zaps quite closely, and I was shocked to see that many nostr devs have no idea what a UTXO is, don't know what "coin control" is1, and so on.

This is worrisome.

Cryptography is hard. There's a million ways to make mistakes that lead to catastrophic loss. To quote Phil Zimmermann: "Most people don’t realize how fiendishly difficult it is to devise an encryption algorithm that can withstand a prolonged and determined attack by a resourceful opponent."

Putting a bounty on every npub is a surefire way to bring prolonged and determined attackers.2

I remain steadfast in my initial assessment of this proposal:

NACK

Footnotes

  1. Let's call it coin selection, shall we? https://bitcoinops.org/en/topics/coin-selection/

  2. Npubs are controlled by people, and it is those people that will be kidnapped (or worse).

@erskingardner
Copy link
Copy Markdown
Contributor

I strongly agree with all the NACKs here for all the reasons that have already been outlined.

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 26, 2026

But does that mean that a bitcoin wallet should encourage users to use "bacon bacon bacon bacon..." as their seed phrase? Of course not. These types of seeds are dangerously insecure.

You can also use any string of characters as a password, but that doesn't mean that we should build software that auto-suggests hunter2 as the password for every user, or allow weak passwords like 123456.

You really just can't resist raising the specter of those needing 24/7 guardianship/care managing to use L1-L∞ compatible technology with ease, can you? No mentally competent person would follow that encouragement, allow anyone under their care to be encouraged all the way to harm, nor would anyone, who is mentally competent, think a productive use of their time would be to actually try to encourage other mentally competent people to do that. Beyond parody.

Reusing cryptographic keys across purposes goes against all the best practices we know

So does having P2TR UTXOs that never had to do with "onchain zaps", which you have to keep on the move or spread so thin that likely no CRQC operator (likely totalitarian state actors) would even bother cracking your keys. Oh no, I've just lost plausible deniability because I didn't practice perfect hygiene while moving them!
Versus UTXOs which can safely be at rest under p2pkh/p2wpkh addresses written in the backshore sand of a desolate beach on a cold winter's day.

Taproot going mainnet as-is was a mistake.

The question at hand is not "is this possible?"

The question at hand is: should this be a NIP?

I think the only sensible answer to that question is a resounding NO.

You think https://github.com/nostr-protocol/nips/blob/master/04.md is the only NIP that can ever have warnings against itself included & THIS NIP being merged won't lead to disinfectant by hypernova-level sunlight? Warnings divided across platforms, few even having a link to this PR in their respective threads, without one authoritiative target to focus the beams on, OTOH...

Apparently it took years from 01 to 44 for https://github.com/search?q=repo%3Anostr-protocol%2Fnips%20quantum&type=code to be explicitly acknowledged. And, didn't NIST already reach Round 3 of its PQC standardization process (to replace vulnerable algorithms like Schnorr and ECDSA) by July 2020, just before NIP-01 was published?

It's ~3 years past time for this NIP with warnings from all angles about doing what started? being done with npubs in 2023 (if not earlier & just not discovered yet).

P.S.

https://x.com/TaoistBitcoiner/status/1676276971821572109

The problem with using immutable identifiers based on our biometrics is that they can never be changed, so if/when leaked, the security breach of our ID is permanent.
Our #nostr identities have similar key management issues, but at least those are disposable & psuedo-anonymous."

https://x.com/mdhardcastle/status/1893736080437916065

"npubs (nsecs) are disposable, they are not an account or an identity.
This is not really understood by many people even on NOSTR"

And yet even we who understand, persist.

@vitorpamplona
Copy link
Copy Markdown
Collaborator

vitorpamplona commented May 26, 2026

Reusing cryptographic keys across purposes goes against all the best practices we know

I think you are on the wrong protocol. The ONLY point that Nostr made from an innovation perspective was to acknowledge the risks and work around the flaws of reusing a single pubkey for everything on the web. You want something Nostr itself cannot provide. When it tries to provide, the UX suffers so much that our products either have to become trusted/centralized or they simply cease to be usable.

The reason Bitcoin works is that the chain is public. Every stack that has tried to make Bitcoin private has failed to build a UX that users can truly depend on for life. People get pissed when things fail, but that is fine because the chain is always there as a fallback. These stacks have always been an "experiment" and may never evolve from there.

The chain will always work

On Nostr, we have been trying to make these shitty protocols work without any fallback. When things fail, our users get pissed because there isn't any stable fallback.

This PR was the first attempt to create something that NEVER fails. I stress. NEVER is truly NEVER. 30 years from now, the funds will be there. We cannot say that for any other wallet solution out there. And users are tired of how flimsy these solutions are.

@alexgleason
Copy link
Copy Markdown
Member Author

https://soapbox.pub/blog/onchain-zaps-in-ditto

@callebtc
Copy link
Copy Markdown

  • Privacy nightmare
  • Will never scale beyond a few people
  • Harmful to Bitcoin by bloating the UTXO set
  • Permanent linkage of your social profile and your personal finances and potentially live savings

NACK

@TheButterZone
Copy link
Copy Markdown

TheButterZone commented May 31, 2026

This PR was the first attempt to create something that NEVER fails. I stress. NEVER is truly NEVER. 30 years from now, the funds will be there. We cannot say that for any other wallet solution out there. And users are tired of how flimsy these solutions are.

I was with you up 'til here... this most likely would be true, if only hardened public key hashed addresses derived from nsec+passphrase were the standard everyone opted to use (#2360), not unhardened, CRQC-vulnerable Taproot. Who will be most likely to be the first to achieve/control CRQC? Totalitarians/nation-states who will seize the peoples' means of economic liberty, as always - whether people within their borders or without. The marketing & implementation of Taproot/Schnorr signatures into mainnet bitcoin couldn't have been written by totalitarians any better. It's well past time to destroy their trap & make all BTC hardened again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.