← Back to Bitcoin Improvement Proposals
BIP 352specificationCompleteprivacypaymentsaddressestransactions

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 reviews
josibake·Updated Mar 29, 2026·0 reviews·0 attestations·View source
Collections:BIPs — Merged

Specification

  BIP: 352
  Layer: Applications
  Title: Silent Payments
  Authors: josibake 
           Ruben 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
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 (i.e. calculating P = B + hash(b·A)·G 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 include an integer in the following manner:

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

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
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. It should also be noted that the order in which these outputs appear in the transaction does not affect the outcome.

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
Bob must calculate the same input_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. 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
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 = Bspend + hash(input_hash·a·Bscan || 0)·G
Bob detects this payment by calculating P0 = Bspend + hash(input_hash·bscan·A || 0)·G with his online device and can spend from his cold storage signing device using (bspend + hash(input_hash·bscan·A || 0)) mod n 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 + hash(bscan || m)·G where m is an incrementable integer starting from 1
  • Publish (Bscan, B1), (Bscan, B2) etc.
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 = 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
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. 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 truncatedview full spec at source]

Discussion (0 threads)

Loading discussions...