Silent Payments
This document specifies a protocol for static payment addresses in Bitcoin without on-chain linkability of payments or a need for on-chain notifications.
No reviewsSpecification
BIP: 352 Layer: Applications Title: Silent Payments Authors: josibakeRuben Somsen Sebastian Falbesoner Status: Complete Type: Specification Assigned: 2023-03-09 License: BSD-2-Clause Discussion: 2022-03-13: https://gist.github.com/RubenSomsen/c43b79517e7cb701ebf77eec6dbb46b8 [gist] Original proposal 2022-03-28: https://gnusha.org/pi/bitcoindev/CAPv7TjbXm953U2h+-12MfJ24YqOM5Kcq77_xFTjVK+R2nf-nYg@mail.gmail.com/ [bitcoin-dev] Silent Payments – Non-interactive private payments with no on-chain overhead 2022-10-11: https://gnusha.org/pi/bitcoindev/P_21MLHGJicZ-hkbC4DGu86c5BtNKiH8spY4TOw5FJsfimdi_6VyHzU_y-s1mZsOcC2FA3EW_6w6W5qfV9dRK_7AvTAxDlwVfU-yhWZPEuo=@protonmail.com/ [bitcoin-dev] Silent Payment v4 (coinjoin support added) 2023-08-04: https://gnusha.org/pi/bitcoindev/ZM03twumu88V2NFH@petertodd.org/ [bitcoin-dev] BIP-352 Silent Payments addresses should have an expiration time Version: 1.0.2
Introduction
Abstract
This document specifies a protocol for static payment addresses in Bitcoin without on-chain linkability of payments or a need for on-chain notifications.
Copyright
This BIP is licensed under the BSD 2-clause license.
Motivation
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 (see Appendix A: Light Client Support).
The design keeps collaborative transactions such as CoinJoins and inputs with MuSig and FROST keys in mind, but it is recommended that the keys of all inputs of a transaction belong to the same entity as there is no formal proof that the protocol is secure in a collaborative setting.
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 upgradeable
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, · refers to elliptic curve scalar multiplication, G represents the generator point for secp256k1, and n represents the curve order 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. For the full protocol specification, see Specification.
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 = B + hash(a·B)·G
- Encode P as a BIP341 taproot output
Creating more than one output
In order to allow Alice to create more than one output for Bob, we include an integer in the following manner:
- Let k = 0
- Let P0 = B + hash(a·B || k)·G
- For additional outputs:
Bob detects this output the same as before by searching for P0 = B + hash(b·A || 0)·G. Once he detects the first output, he must:
- Check for P1 = B + hash(b·A || 1)·G
- 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
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 destinations Pi. To prevent this, Alice should include an input hash in the following manner:
- Let input_hash = hash(outpoint || A)
- Let P0 = B + hash(input_hash·a·B || 0)·G
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. This significantly reduces Bob's scanning requirement, makes light client support more feasible, and protects Alice's privacy in collaborative transaction protocols such as CoinJoin.
Alice performs the tweak with the sum of her input private keys in the following manner:
- Let a = a1 + a2 + ... + an
- Let input_hash = hash(outpointL || (a·G)), where outpointL is the smallest outpoint lexicographically
- Let P0 = B + hash(input_hash·a·B || 0)·G
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 = Bspend + hash(input_hash·a·Bscan || 0)·G
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 + hash(bscan || m)·G where m is an incrementable integer starting from 1
- Publish (Bscan, B1), (Bscan, B2) etc.
- Let P0 = Bspend + hash(input_hash·bscan·A || 0)·G
- Subtract P0 from each of the transaction outputs and check if the remainder matches any of the labels (hash(bscan || 1)·G, hash(bscan || 2)·G etc.) that the wallet has previously used
Labels for change
Bob can also use labels for managing his own change outputs. We reserve m = 0 for this use case. 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. It is important that the wallet never hands out the label with m = 0 in order to ensure nobody else can create payments that are wrongly labeled as change.
While the use of labels is optional, every receiving silent payments wallet should at least scan for the change label when recovering from backup in order to ensure maximum cross-compatibility.
Specification
We use the following functi
[Content truncated — view full spec at source]
Related Specs
Discussion (0 threads)
Loading discussions...