Hi all,
After what has seemed like an eternity of refining and tweaking (pun intended) 
the original write-up proposed by Ruben Somsen back in March 2022, we'd like to 
submit a Silent Payments BIP for your consideration and review.


For convenience, the overview from the BIP is in plain text below. Please note: 
the overview is not the full specification; the full specification can be found 
at https://github.com/bitcoin/bips/pull/1458/files , along with a WIP 
implementation for Bitcoin Core at 
https://github.com/bitcoin/bitcoin/pull/27827 .



Looking forward to hearing your thoughts!


-- Ruben, Josie


== Silent Payments ==

Using a new address for each Bitcoin transaction is a crucial aspect of 
maintaining privacy. This often requires a secure interaction between sender 
and receiver so that the receiver can hand out a fresh address, a batch of 
fresh addresses, or a method for the sender to generate addresses on-demand, 
such as an xpub.

However, interaction is often infeasible and in many cases undesirable. To 
solve for this, various protocols have been proposed which use a static payment 
address and notifications sent via the blockchain. These protocols eliminate 
the need for interaction, but at the expense of increased costs for one-time 
payments and a noticeable footprint in the blockchain, potentially revealing 
metadata about the sender and receiver. Notification schemes also allow the 
receiver to link all payments from the same sender, compromising sender privacy.

This proposal aims to address the limitations of these current approaches by 
presenting a solution that eliminates the need for interaction, eliminates the 
need for notifications, and protects both sender and receiver privacy. These 
benefits come at the cost of requiring wallets to scan the blockchain in order 
to detect payments. This added requirement is generally feasible for full nodes 
but poses a challenge for light clients. While it is possible today to 
implement a privacy-preserving light client at the cost of increased bandwidth, 
light client support is considered an area of open research

== Goals ==

We aim to present a protocol which satisfies the following properties:

-   No increase in the size or cost of transactions

-   Resulting transactions blend in with other bitcoin transactions and can’t 
be distinguished
-   Transactions can’t be linked to a silent payment address by an outside 
observer
-   No sender-receiver interaction required
-   No linking of multiple payments to the same sender
-   Each silent payment goes to a unique address, avoiding accidental address 
reuse
-   Supports payment labeling
-   Uses existing seed phrase or descriptor methods for backup and recovery
-   Separates scanning and spending responsibilities
-   Compatible with other spending protocols, such as CoinJoin
-   Light client/SPV wallet support
-   Protocol is upgrade-able


== Overview ==

We first present an informal overview of the protocol. In what follows, 
uppercase letters represent public keys, lowercase letters represent private 
keys, || refers to byte concatenation, and G represents the generator point for 
secp256k1. Each section of the overview is incomplete on its own and is meant 
to build on the previous section in order to introduce and briefly explain each 
aspect of the protocol.

=== Simple case ===

Bob publishes a public key B as a silent payment address. Alice discovers Bob's 
silent payment address, selects a UTXO with private key a, public key A and 
creates a destination output P for Bob in the following manner:

-   Let P = hash(a·B)·G + B
-   Encode P as a BIP341 taproot output


Since a·B == b·A (Elliptic Curve Diffie-Hellman), Bob scans with his private 
key b by collecting the input public keys for each transaction with at least 
one unspent taproot output and performing the ECDH calculation until P is found 
(e.g. calculating P = hash(b·A)·G + B and seeing that P is present in the 
transaction outputs).

=== Creating more than one output ===

In order to allow Alice to create more than one output for Bob, we included an 
integer in the following manner:

-   Let n = 0
-   Let P0 = hash(a·B || n)·G + B
-   For additional outputs:
    -   Increment n by one (n++)
    -   Let Pi = hash(a·B || n)·G + B

Bob detects this output the same as before by searching for P0 = hash(b·A || 
0)·G + B. Once he detects the first output, he must:

-   Check for P1 = hash(b·A || 1)·G + B
-   If P1 is not found, stop
-   If P1 is found, continue to check for P2 and so on until an additional 
output is not found


Since Bob will only perform these subsequent checks after a transaction with at 
least one output paying him is found, the increase to his overall scanning 
requirement is negligible.

=== Preventing address reuse ===

If Alice were to use a different UTXO from the same public key A for a 
subsequent payment to Bob, she would end up deriving the same destination P. To 
prevent this, Alice should include a hash of the outpoint in the following 
manner:

-   Let outpoint_hash = hash(txid || vout)
-   Let P0 = hash(outpoint_hash·a·B || 0)·G + B


Bob must include the same outpoint_hash when scanning.

=== Using all inputs ===

In our simplified example we have been referring to Alice’s transactions as 
having only one input A, but in reality a Bitcoin transaction can have many 
inputs. Instead of requiring Alice to pick a particular input and requiring Bob 
to check each input separately, we can instead require Alice to perform the 
tweak with the sum of the input public keys[3]. This significantly reduces 
Bob's scanning requirement, makes light client support more feasible[4], and 
protects Alice's privacy in collaborative transaction protocols such as 
CoinJoin[5].

Alice performs the tweak with the sum of her input private keys in the 
following manner:

-   Let outpoints_hash = hash(txid0 || vout0 || … txidn || voutn)
-   Let a = a0 + a1 … + an
-   Let P0 = hash(outpoints_hash·a·B || 0)·G + B


=== Spend and Scan Key ===

Since Bob needs his private key b to check for incoming payments, this requires 
b to be exposed to an online device. To minimize the risks involved, Bob can 
instead publish an address of the form (Bscan, Bspend). This allows Bob to keep 
bspend in offline cold storage and perform the scanning with the public key 
Bspend and private key bscan. Alice performs the tweak using both of Bob’s 
public keys in the following manner:

-   Let P0 = hash(outpoints_hash·a·Bscan || 0)·G + Bspend



Bob detects this payment by calculating P0 = hash(outpoints_hash·bscan·A)·G + 
Bspend with his online device and can spend from his cold storage signing 
device using (hash(outpoints_hash·bscan·A) + bspend) mod p as the private key.

=== Labels ===

For a single silent payment address of the form (Bscan, Bspend), Bob may wish 
to differentiate incoming payments. Naively, Bob could publish multiple silent 
payment addresses, but this would require him to scan for each one, which 
becomes prohibitively expensive. Instead, Bob can label his spend public key 
Bspend with an integer m in the following way:

-   Let Bm = Bspend + m·G
-   Publish (Bscan, B0), (Bscan, B1) …



Alice performs the tweak as before using one of the published (Bscan, Bm) 
pairs. Bob detects the labeled payment in the following manner:


-   Let P0 = hash(outpoints_hash·bscan·A || 0)·G + Bspend
-   Subtract P0 from each of the transaction outputs and check if the remainder 
matches any of the labels (1·G, 2·G ..) that the wallet has previously used



It is important to note that an outside observer can easily deduce that each 
published (Bscan, Bm) pair is owned by the same entity as each published 
address will have Bscan in common. As such, labels are not meant as a way for 
Bob to manage separate identities, but rather a way for Bob to determine the 
source of an incoming payment.

=== Labels for change ===

Bob can also use labels for managing his own change outputs. To do so, he can 
reserve a secret change label in the following manner:

-   Let Bchange = Bspend + hash(bscan)·G



Now, whenever Bob is spending (to a silent payment address or otherwise), he 
can create a change output for himself using the silent payments protocol and 
his change label in the following manner:



-   Let a = a0 + a1 … + an represent the private keys of the inputs Bob is 
using to fund the transaction
-   Let Pchange = hash(outpoints_hash·a·Bchange || 0)·G + Bspend



This gives Bob an alternative to using BIP32 for managing change, while still 
allowing him to know which of his unspent outputs were change when recovering 
his wallet from the master key. The change label needs to remain a secret in 
order to ensure nobody else can label payments as change.


Sent with Proton Mail secure email.

Attachment: publickey - josibake@protonmail.com - 0x616516B8.asc
Description: application/pgp-keys

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
bitcoin-dev mailing list
bitcoin-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev

Reply via email to