6

Imagine a web page that wants to accept Bitcoin donations. A naive approach is to provide a single address on the page and that's it. The problem here is that the address is known to everyone and if the money ever moves, the address is being reused for new donations after the first spend.

OK, so how can we do better? We can have xpub and generate a new address every time ... every time what? The first basic strategy would be to generate a new address as soon as someone sends a donation to the previously generated one. The problem here is that an active monitoring of the web page by a robot simply reveals all the addresses again.

Can we do better? We can, for example, generate a new address per IP address. Doing this, the robot would always see one address that is dedicated to its IP address and unless someone from the robot's network under the same IP address donated, the robot could not reveal anything useful. The problem here is that if we assume not very high conversion rate, we generate a lot of addresses and most of them never receive any donation. This causes a problem with seed recovery, where there usually is a gap limit defined for the maximum number of empty addresses that are scanned before the scan is terminated. I assume this is quite wallet specific rule, but I assume in general, the problem exists here (does it really?).

So how can we do better? Say we want to use a cold storage using a 24 word seed + passphrase and we are happy to run Bitcoin Core together with the web page. How can we solve donation in a way that is manageable, can be recovered from seed, and at the same time optimizes for privacy? Does a solution already exists somewhere (for example BTCPayServer)? If so, how does it work and what are the privacy properties of such a solution?

2
  • Why are you against reuse?
    – MCCCS
    Jun 26 at 12:10
  • Reusing is primarily known to be bad for privacy. For example, let's say you don't want everyone to know how much you received from the donations in total. If you reuse just one address, everyone will know. The primary concern in this question is to keep such information from an attacker who actively monitors your donation page.
    – Wapac
    Jun 27 at 17:07
1

The first basic strategy would be to generate a new address as soon as someone sends a donation to the previously generated one.

This is not a good strategy. Consider Alice opens the donation page, looked at the address and decided to send nothing. Bob will also see the same address and send some bitcoin. Alice can track this donation or at least know some information about the inputs and history related to transaction.

Can we do better? We can, for example, generate a new address per IP address.

Few tools are available to use different IP on each request. So, this may not be the best approach.

The problem here is that if we assume not very high conversion rate, we generate a lot of addresses and most of them never receive any donation. This causes a problem with seed recovery, where there usually is a gap limit defined for the maximum number of empty addresses that are scanned before the scan is terminated. I assume this is quite wallet specific rule, but I assume in general, the problem exists here

Yes, according to my understanding 'Gap Limit' is an issue. The biggest issue in trying to solve this problem of privacy in donation addresses.

Does a solution already exists somewhere (for example BTCPayServer)? If so, how does it work and what are the privacy properties of such a solution?

BTCPayServer creates a new bitcoin address every time you open the donation page.

Example: https://btcpayjungle.com/api/v1/invoices?storeId=FSt2N7kxe7m5Nzbu5xxqSB83faZQG44Etx2wp266C4rC&price=10&currency=USD

I had created a new bitcoin wallet in electrum which has default gap limit of 20. I could find all the 20 addresses in my wallet by opening the above link 20 times. 21st request to open the page returned a new address: bc1qpzt7hax5cade0yu4grqn4aat62hdq9jj9cxuav which I could not see in my wallet.

I had to increase the gap limit by running the below command, relaunch electrum to see the address:

wallet.change_gap_limit(21)

So BTCPayserver is good for privacy in this case but will have issues managing wallet with huge gap limit if someone tries to attack.

Joinmarket donation page also provides a new bitcoin address every time you refresh the page: https://bitcoinprivacy.me/joinmarket-donations. Chris Belcher shared on twitter that lot of addresses are imported in a watch-only wallet(Core).

Other solutions:

Reusable Payment Codes: https://support.samourai.io/article/68-what-are-paynyms


This is an interesting problem to solve and I will update the answer if I find better solution or a way to use Bitcoin Core for donations which improves privacy and no other major issues.

3
  • Thanks for the comments. I am aligned with you on what you said, but I do not consider that really a (final) solution to the question. PayNyms sound interesting but it seems that it is not widely supported feature. Importing tons of addresses is a solution, but it is somewhat unsatisfying. So let's see if someone else proposes a better solution.
    – Wapac
    Jun 16 at 11:19
  • Regarding "Few tools are available to use different IP on each request. So, this may not be the best approach." - this is wrong in my opinion as such tools or VPNs or anything really that changes the IP address does not make anything worse for us. For us it is important not to reveal a significant amount of our addresses that we show to other users to the attacker, but it is OK to show large amount of addresses to the attacker as far as we can handle the amount. In order for this to matter, the attacker would need to have access to a lot (100,000?) of IP addresses with very little cost.
    – Wapac
    Jun 16 at 16:38
  • Related project discussion that you may find interesting: github.com/BlockchainCommons/Community/discussions/45
    – Prayank
    Jun 24 at 9:38
1

Great question!

For each anonymous visitor who clicked [Donate]:

  • generate a new, high-entropy URL that is public to access but impossible to guess (additionally, it can expire after some time)
  • derive a new Bitcoin address based on xpub and the counter; this address is dedicated to this specific donation attempt

Even if anonymous visitor abandons the process without paying, her unique address is never reused. It is "wasted" in terms of the address space gap.

Other anonymous visitors will not be able to discover any past or future addresses because they can't guess the URL-s.

The only drawback is theoretical risk of pointless vandalism: one can click [Donate] in a loop, increasing the number of unused addresses in your wallet. This isn't really a big issue because most wallets can be configured to arbitrary gap. I also never heard of such vandalism attempts happening in practice.

Now, the most pragmatic way to go aobut it is use existing open source, self-hosted donations processors like:

3
  • Yeah, this is similar as my attempt with IP addresses - when someone wants to donate (clicks), generate a new address in case it is a new IP, and deliver same as before address if the IP has been seen before (and address not used). This does have the same problem with the funds recovery due to the gap. It is true that many wallets do have configurable gaps, but not all of them. And even without vandalism it will happen that the common gap of 20 will be reached. I guess that BTCPayServer and CPP do solve the gap for you here, right?
    – Wapac
    Jun 27 at 17:13
  • 1) I wouldn't say it's similar, the IP based approach is incorrect. On one hand thousands of users can easily share the same public IP address in some circumstances. At the same time, a single user can have different IP address every couple seconds (just Ctrl+Shift+L in Tor Browser or reset VPN). 2) No, neither BTCPay nor CypherpunkPay "solve" the gap problem. The problem is inherent to never-reusing any address once shown and cannot be "solved" otherwise than on the donation recipient wallet side. The software can guide the recipient about minimum necessary gap though! Jun 27 at 20:13
  • I do agree a user can obtain multiple IP addresses and many users can share one IP address. But it does not seem too relevant to the prevention of the attack I described. Point was to prevent attacker to reveal significant part of the donations of other people. Unless the attacker can possess (and repossess) many IP addresses that are used by people who actually donate, there is no problem. So the best the attacker could hope is to gain information about donations from Tor users. Of course if there is no solution then this is pointless and we can just assign new address each time.
    – Wapac
    Jun 29 at 9:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.