---
title: "How silent payments work · BIP 352, drawn and with real numbers"
description: "A visual walk through BIP 352 silent payments: the two keys, the exact derivation with real test vector values, why input_hash exists, labels, the scanning cost, and the honest limitations."
url: "https://silentpayments.net/how"
language: "en"
---

> A visual walk through BIP 352 silent payments: the two keys, the exact derivation with real test vector values, why input_hash exists, labels, the scanning cost, and the honest limitations.

_This page has three detail levels in HTML: Easy, Advanced and Cypherpunk._
_This twin carries the Advanced and Cypherpunk text, which is the complete version._

BIP 352 · Status: Complete · Version 1.1.1

# How a payment finds you without anyone announcing it

Silent payments solve one problem, and it is a narrow one. Your wallet already makes a new address for every payment. What it cannot do is get that address to a payer without you being there. So: give somebody a single string they can keep, and still make every payment land somewhere new. No message to you, no notification transaction, no extra bytes on the chain, and no way for two people who paid you to work out they paid the same person.

The trick is one sentence long. **The sender’s own transaction inputs already contain a public key, and it is already on the chain.** That is enough for both sides to agree on a secret nobody else can compute. Everything below is the detail.

§ 01 · The two keys

## Why a silent payment address holds two keys, not one

Finding an incoming payment requires a multiplication with a _private_ key. If your wallet had only one key, that key would have to sit on a machine that is always online, and that same key would spend your money. So the address carries two.

> **Diagram.** A seed derives a scan key and a spend key. The scan key can find payments but cannot spend them.

_The split is what makes an always-on scanner safe. A machine holding `b_scan` and the public `B_spend` can see every payment you receive and compute every output key, and still cannot move a satoshi. Handing that scan key to a service is a real privacy decision, not a security one._

- **Address format**: bech32m, human readable part `sp`, version character `q`
- **Payload**: 66 bytes: the compressed `B_scan` then the compressed `B_spend`
- **Length**: 116 characters on mainnet, 117 on testnet and signet where the prefix is `tsp`
- **Not in the spec**: `sprt` for regtest is a convention from one Rust crate, not a standard

The spec’s own footnote says “117 characters”, computed with a three-character prefix. Mainnet uses the two-character `sp`, so mainnet addresses are 116. All twelve addresses in the official test vector file are 116.

### Take one apart

A real address from the test vectors, in pieces. Point at a piece to find out what it is.

sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv

**The human readable part.**`sp` on mainnet, `tsp` on testnet and signet. Two characters here rather than three is the entire reason a mainnet address is 116 characters and the specification’s own footnote says 117.

**The separator.** Always the character `1`, which is why it is the one character bech32 does not use anywhere else. Everything to its left is the prefix, everything to its right is data.

**The version.**`q` is zero. A sender meeting versions 1 to 30 must read the first 66 bytes and ignore the rest, so the format can grow. Version 31 is reserved for a change that deliberately breaks old senders.

**B_scan, the public scan key.** 33 bytes, the half that finds payments. Anyone reading your address holds this, and it is useless to them: finding a payment needs the matching private key, which never leaves your wallet.

**B_spend, the public spend key.** 33 bytes, the half every output key is built on. A note on honesty: 33 bytes is 52.8 bech32 characters, so the true boundary between the two keys falls inside a character. This split is at the nearest one.

**The checksum.** Six bech32m characters. Mistype one character anywhere in the address and this will not match, so your wallet refuses rather than sending money to nobody.

§ 02 · The derivation

## The whole thing, one step at a time

Every number printed in this diagram is real. They are the values from test case 0 of the official BIP 352 test vectors, recomputed from scratch and checked against the file. If you implement this and get these numbers, you got it right.

> **Diagram.** Alice picks her inputs. Two are eligible to contribute to the shared secret, one is not.

> **Diagram.** The private keys of the eligible inputs are added into a single number.

> **Diagram.** The smallest outpoint is chosen and serialised with its bytes reversed.

> **Diagram.** The outpoint and the summed public key are hashed together into input_hash.

> **Diagram.** Alice computes the shared secret from her private key and Bob's public scan key.

> **Diagram.** The shared secret and a counter produce the destination key.

> **Diagram.** On the chain, a silent payment is indistinguishable from an ordinary taproot payment.

> **Diagram.** Bob recomputes the same shared secret from public data and his own scan key.

Step 01

### Alice picks her coins

Only four kinds of input can contribute to the secret. Anything with branches or several keys, like a multisig script, is excluded, because a hostile co-signer could re-sign with a different key set and the payment would land somewhere Bob never looks. Excluded inputs can still pay the fee.

Step 02

### She adds her private keys together

One number, not one per input. That single change, made in October 2022, is what halved the receiver’s work and opened the door to collaborative transactions. Taproot keys are x-only, so both sides have to agree on the sign.

Step 03

### She picks the smallest outpoint

Lexicographically smallest across every input, serialised the way it appears in the raw transaction, which is byte reversed from the txid you read on an explorer. Using one fixed outpoint makes the result independent of input ordering, and keeps it computable on a hardware signer with very little memory.

Step 04

### She hashes both together

This is `input_hash`, and it is the part people skip. It makes the secret unique to this transaction, and it commits to `A` so that a malicious sender cannot pick a key that forces a collision. Take it out and the protocol still appears to work, while quietly reintroducing address reuse.

Step 05

### Diffie-Hellman

Alice can compute this because `a` is hers and `B_scan` is printed in the address she was given. Nobody watching can, because they hold neither private half. The mathematics is from 1976 and has not needed changing.

Step 06

### The output key

Hash the secret with a counter, add the result to `B_spend`, and that is the destination. Paying the same person twice in one transaction just increments the counter. Every output the wallet generates must actually be broadcast: drop one and the receiver’s scan stops there and misses everything after it.

Step 07

### Nothing announces itself

What reaches the chain is an ordinary taproot payment. No marker, no notification, no extra byte. This is why nobody can count silent payments, including the firms paid to count things, and why the anonymity set is every taproot payment rather than every silent payment.

Step 08

### The two secrets meet

Bob reads the input public keys and the outpoints from the transaction itself, so he can compute the same `input_hash`, and `b_scan · A` gives him the identical point Alice got from `a · B_scan`. That is the whole reason there is no notification: the data was always there.

### The same walk, in real numbers

Test case 0 from `bip-0352/send_and_receive_test_vectors.json`, two P2PKH inputs paying one silent payment address. Every line was recomputed and matched against the file.

```
# two inputs
in[0] txid f4184fc5…831e9e16 vout 0   a₁ = eadc7816…e5dff3b1
in[1] txid a1075db5…fbf5d48d vout 0   a₂ = 93f5ed90…9408aad16

# serialised outpoints are byte reversed. this is the one exception in the spec.
in[0] → 169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f4 00000000
in[1] → 8dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d415db55d07a1 00000000
outpoint_L = 169e1e83…c54f18f400000000        # in[0] is smaller# sums
a = 7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86
A = 032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee

# the binding hashinput_hash = 5bfe5321d759e01a2ac9292f0f396ff9c3d8b58d89ccb21a6922e84bb7ad0668

# what an index server serves to a light client: input_hash · Atweak      = 024ac253c216532e961988e2a8ce266a447c894c781e52ef6cee902361db960004

# the shared secret, computed independently on both sides
sender  : input_hash · a · B_scan = 028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d
receiver: b_scan · (input_hash · A) = 028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d# the output
t₀ = f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6
P₀ = B_spend + t₀·G
P₀ x-only    = 3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1
scriptPubKey = 5120 3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1
             # an ordinary taproot output. that is the entire disguise.
```

- **The three tags**: `BIP0352/Inputs``BIP0352/SharedSecret``BIP0352/Label`
- **Tagged hash**: `SHA256(SHA256(tag) ‖ SHA256(tag) ‖ x)`, the BIP 340 convention
- **Output type**: Always P2TR in version 0. No optionality, so everyone lands in the same anonymity set
- **Signature hash**: `SIGHASH_ALL` or `DEFAULT`. `ANYONECANPAY` is unsafe: the input set would be free to change after signing, and every derived output would move

§ 03 · The part people skip

## Why `input_hash` is in there

Take it out and the protocol still appears to work. It also quietly reintroduces the exact problem it was written to solve.

> **Diagram.** Without input_hash two payments from the same key produce the same output address. With it they produce different ones.

_The hash also commits to `A`, not just the outpoint. Without that, a malicious sender could solve for a private key `a′` that cancels the difference and _force_ the collision on purpose. Committing to `A = a·G` inside the hash turns that into a fixed point problem nobody can solve._

§ 04 · Labels

## Many addresses, one scan

One identity can hand out addresses that look completely different, and still cost the same to scan. Add a tweak to the spend key before encoding:

```
Bₘ = B_spend + hash(ser_256(b_scan) ‖ m)·G
     tag: BIP0352/Label
```

Detection costs nothing extra. The wallet computes `Pₔ` as usual, then subtracts it from the output and looks the difference up in a small precomputed table. One lookup, not one extra multiplication per label.

**Label 0 is reserved for your own change, and must never be handed out.** If somebody else had it they could create outputs your wallet would file as its own change. Scan for it always, even if you use no other labels, so a wallet restored in different software still finds it.

#### The misconception worth killing

> **Diagram.** Three labelled addresses all share the same scan key, so an observer can tell they belong to one person

Look at the highlighted middle of all three. That is the same encoded `B_scan`, because labels only tweak the spend half. Anyone holding two of your labelled addresses can see at a glance they are one person.

**Labels sort your incoming payments. They are not separate identities.** The payments themselves stay unlinkable. The published strings do not.

§ 05 · The bill

## Somebody has to scan

Nothing is free. The cost of removing the notification, the round trip and the on-chain overhead is that your wallet has to look at transactions rather than being told about them. Here is the real size of that bill.

How long has your wallet been offline?

30 days

1 day3 months1 year2 years

blocks to check4,320

transactions in them3,834,000

tweak data to fetch42 MB

LaptopM1 MacBook Pro, 10 core13.4 s

DesktopCore Ultra 9 285K, 24 core6.7 s

Graphics cardRTX 5080, CUDA0.22 s

Rates are the published Frigate benchmarks: 286,404 transactions per second on the laptop, 569,123 on the desktop, 17,188,956 on the graphics card. Blocks are counted at 144 a day and 887.5 transactions each, which is what Frigate measured. Tweak data is estimated at 10 kB per block, the middle of the 7 to 12 kB the specification reports for the chain as it is today. Your phone is not on this list, and that is the honest part: the unsolved problem is not the arithmetic, it is fetching that data without telling a server which payments are yours.

| Hardware | 1 day | 1 month | 1 year | 2 years |
|---|---|---|---|---|
| M1 MacBook Pro, 10 core CPU | 2.7 s | 20.0 s | 3 m 28 s | 7 m 47 s |
| Core Ultra 9 285K, 24 core CPU | · | · | 1 m 44 s | 3 m 50 s |
| RTX 5080, CUDA | · | · | 3.5 s | 7.7 s |
| Two RTX 5090, CUDA | · | · | 2.1 s | 3.2 s |

A year of chain in three and a half minutes on a laptop is not a research problem. The research problem is the phone: a light client has to get the 33 bytes per transaction from somewhere, and getting them without telling a server which payments are yours is the unsolved part. The spec says so itself: _“It is still an open question as to how Bob can source the 33 bytes per transaction in a trustless manner.”_

#### Bandwidth today

Roughly 7 to 12 kB per block, so 30 to 50 MB a month. If every transaction on the chain became taproot it would rise toward 100 kB per block.

#### The cut-through trick

Half of all transactions have their taproot outputs spent within one block. A wallet scanning every three days can skip those entirely and land near 30 MB a month.

#### The denial of service fix

A single hostile 23,230 output transaction used to take 165 seconds to scan. Version 1.1.0, March 2026, capped recipients per group at `K_max = 2323`. Now 17 seconds, and no real wallet notices, because a 2,323 output transaction is already 99,959 vbytes and one more output breaks the relay limit.

§ 06 · Honesty

## What silent payments do not do

### They do not do Lightning, and that is what the second parameter is for

Everything on this page is on-chain. A silent payment is a bitcoin transaction, with a confirmation to wait for and a fee to pay, which is the wrong shape for paying for a coffee.

So the same record can carry a **BOLT 12 offer** beside the address, as `lno`. A Lightning wallet reads that one, a silent payments wallet reads the address, and the payer never has to ask which you wanted. One name, both rails, published once.

The asymmetry is worth knowing. A silent payment address is two public keys and nothing else, so it keeps working forever. An offer may carry blinded paths tied to a node or a Lightning service provider, so it can go stale, and it carries no checksum, so a swapped character publishes cleanly and nothing detects it. That is why the address is the required leg here and the offer is the optional one.

### An exchange cannot pay you privately

The sender needs the private keys of the coins being spent. If you withdraw from a custodian to a silent payment address, the custodian has to implement this, and almost none have. Ruben Somsen flagged it in the original 2022 proposal and it is still open: “No solution is known at this time, so as it stands this is a limitation of the protocol.”

### CoinJoin is not proven safe

The spec is blunt: 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.” Doing it properly needs blinded key exchange with discrete log equality proofs, which is why BIP 374 exists as a separate document.

### There is no Lightning here

A silent payment is an on-chain taproot output derived from on-chain inputs. It has no meaning inside a payment channel. The Lightning shaped answer to the same problem is a BOLT 12 offer, and a payment name can carry both at once.

### Fee bumping can break it

Change the input set and every derived output moves, because the inputs are the ingredients. A wallet that replaces a transaction without re-deriving sends money to a key nobody can find. Electrum deliberately sets the sequence number so unsafe fee bumps cannot happen.

### Old software cannot pay you

The spec says it: silent payments are “not compatible with older wallet software or wallets which have not implemented the silent payments protocol.” Which is exactly why the next section is uncomfortable reading.

### What it does do, completely

One address you can publish forever, a fresh unlinkable output for every payment, no interaction, no notification transaction, no extra bytes, and outputs that are indistinguishable from every other taproot payment on the chain. That is the whole promise and it is delivered.

§ 07 · Reality check

## Who can actually do this

The cryptography is finished. The wallet layer is thin. The merchant layer does not exist. Anyone telling you otherwise is selling something.

| Software | Send | Receive | Since |
|---|---|---|---|
| Sparrow Wallet | yes | yes | 2.3.0 · 2025-10-03 · receive in 2.5.0 · 2026-05-21 |
| Cake Wallet | yes | yes | first merged 2024-05-31 |
| Dana Wallet | yes | yes | experimental |
| BlindBit Desktop | yes | yes | alpha |
| BitBox02 | yes | · | 2024-09-20 |
| Wasabi Wallet | yes | · | 2.7.2 · 2025-11-17 |
| Nunchuk | yes | · | 2026-02-20 |
| BlueWallet | yes | · | bundles the SilentPayments library |
| Electrum | third party plugin, unaudited | · | 2026-07-26 |
| **Bitcoin Core** | no | no | three wallet pull requests still open |
| **BTCPay Server** | no | no | one unanswered request since 2025-12-21 |

The cryptography reached a tagged release of libsecp256k1 on 3 August 2026, in version 0.8.0, four years and four months after the idea was posted to a mailing list. Bitcoin Core still ships nothing to users. That gap is the honest state of play, and it is why a name that a human can type matters: the protocol does not fail on mathematics, it fails on a 116 character string nobody will ever read out.

One number you will not find here, because it cannot exist: how many silent payments have been made. The outputs are ordinary taproot outputs with no marker, so nobody, including chain analysis firms, can count them. If somebody quotes you a figure, it was invented.

Sources

- [BIP 352, the specification](https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki)
- [reference.py, the reference implementation](https://github.com/bitcoin/bips/blob/master/bip-0352/reference.py)
- [The 28 test vectors](https://github.com/bitcoin/bips/blob/master/bip-0352/send_and_receive_test_vectors.json)
- [BIP 374, discrete log equality proofs](https://github.com/bitcoin/bips/blob/master/bip-0374.mediawiki)
- [BIP 375, sending with PSBTs](https://github.com/bitcoin/bips/blob/master/bip-0375.mediawiki)
- [Frigate, and its benchmark numbers](https://github.com/sparrowwallet/frigate)
- [libsecp256k1 0.8.0 changelog](https://github.com/bitcoin-core/secp256k1/blob/master/CHANGELOG.md)
- [Bitcoin Core tracking issue 28536](https://github.com/bitcoin/bitcoin/issues/28536)
- [Light client protocol thread](https://delvingbitcoin.org/t/silent-payments-light-client-protocol/891)
- [Bitcoin Optech topic page](https://bitcoinops.org/en/topics/silent-payments/)
- [Ruben Somsen’s original gist](https://gist.github.com/RubenSomsen/c43b79517e7cb701ebf77eec6dbb46b8)
- [Wallet support tracker](https://silentpayments.xyz/docs/wallets/)

Keep reading

BIP 353

### The name in front of it

How a signed DNS record turns sp1q into something you can say out loud.

2011 to now

### Fifteen years of trying

Stealth addresses, BIP 47, and the one observation that made it cheap.

Free

### Claim a name

No account, no email address. One form, one record, one log entry.
