This PR proposes an early version of Silent Payment (author:@RubenSomsen). In this scheme, the recipient generates a public address, but the sender tweaks the address and the recipient detects the payment by verifying all transactions on the blockchain. An example use case would be private donations.
The purpose of this PR is not a final version, but to start the discussion and get benchmarks based on a real implementation.
This version is built on top of #994 (bitcoin-core/secp256k1) for x-only ECDH support and #23480 (bitcoin/bitcoin) for rawtr()
. Each new silent transaction detected is stored in wallet as a rawtr()
descriptor.
In this implementation, the sender can tweak the recipient address by passing the silent_payment
option to send RPC. The transaction output will be different from the address entered.
For example ./src/bitcoin-cli -regtest -named send outputs="[{\"bcrt1pwlh5xuyrpgfunwyww8cfu78yfs2yqyevl7yturavahh5kgxwdd2q5hzgfu\": 1.1}]" fee_rate=1 options="{ \"silent_payment\": true}"
.
will generate vout
with completely unrelated outputs:
0"vout": [
1 {
2 "value": 1.10000000,
3 "n": 0,
4 "scriptPubKey": {
5 "desc": "rawtr(65b19890c5ca40edb816d26f5f48cd9f3ed51121613b1c2405adc1a6dbbc824a)#8myx9tcu",
6 "address": "bcrt1pvkce3yx9efqwmwqk6fh47jxdnuld2yfpvya3cfq94hq6dkausf9qrfjkgz",
7
8 }
9 },
10 {
11 "value": 2.02499835,
12 "n": 1,
13 "scriptPubKey": {
14 "desc": "rawtr(c45cb3d500bbf8f0c8841e8e011b008781d826c16ee348edb822c0f97419bc4d)#26hcce63",
15 "address": "bcrt1pc3wt84gqh0u0pjyyr68qzxcqs7qasfkpdm353mdcytq0jaqeh3xsuvlykg",
16 }
17 }
18 ]
Any wallet, as long as it has access to private keys, can send silent payments. Thus, this excludes watch-only wallets or wallets with external signers .
But the recipient’s wallet needs a new flag called SILENT_PAYMENT
. This flag allows an additional scan that verifies that the wallet keys match the silent payment scheme. When it detects a silent payment that belongs to the wallet, it is stored in a rawtr()
descriptor.
./src/bitcoin-cli -regtest -named createwallet wallet_name="recipient" silent_payment=true
Therefore, scanning each address for each transaction is potentially prohibitive overhead, so the node can be initialized with keypool=1
or a descriptor with range [0,1] can be imported into a blank wallet. Until there is more benchmark data, it is the safest option. The proposal recommends one static address.
I’ve been running some silent payments on signet using wallets with default keypool and default range, I haven’t noticed any relevant performance drops on the signet node. Apparently this implementation is working as expected but I can’t guarantee that the scheme is implemented correctly or safely, so I’m opening this PR for reviews, modifications and improvements.
There is a new functional test (test/functional/wallet_silentpayment.py
) that can help to better understand the implementation.