silentpayments.net

BIP 352 · Status: Complete · Version 1.1.1

How a payment finds you
without anyone announcing it

Silent payments solve one problem: give somebody a single address 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.

A seed derives a scan key and a spend key. The scan key can find payments but cannot spend them. seed one backup hardened Hot. Safe to expose. b_scan · B_scan m / 352′ / coin′ / account′ / 1′ / 0 finds payments. cannot spend them. Cold. Never online. b_spend · B_spend m / 352′ / coin′ / account′ / 0′ / 0 the only thing that can move a coin. public halves only bech32m, hrp “sp”, version 0 sp1q… 66 bytes of payload. 116 characters on mainnet. The two keys are concatenated, not combined. Anyone reading the address can see both public keys. Neither one lets them find or spend anything.
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.

Alice picks her inputs. Two are eligible to contribute to the shared secret, one is not. 1 · The coins Alice is spending P2WPKH a₁ · counts toward the secret P2TR a₂ · counts, negated if a₂·G has an odd Y P2WSH, 2 of 3 pays the fee. ignored here. Only four input types can contribute: P2TR · P2WPKH · P2SH-P2WPKH · P2PKH Anything with branches or several keys is excluded, because a hostile co-signer could re-sign with a different set of keys and Bob would never find the money.
The private keys of the eligible inputs are added into a single number. 2 · One number, not one per input a = a₁ + a₂ (mod n) A = a·G a 7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86 A = 032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee Two ways to get this wrong Taproot keys are x-only, so both sides must agree on the sign. If a₂·G has an odd Y coordinate, negate a₂. If the sum is zero, abort.
The smallest outpoint is chosen and serialised with its bytes reversed. 3 · The smallest outpoint, byte reversed the txid as an explorer shows you f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16 as it appears in the raw transaction 169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f4 then the output index, four bytes, little endian 00000000 Lexicographically smallest across every input in the transaction, not just the eligible ones, so the result does not depend on how the inputs end up ordered. This is the one place in the whole specification where the bytes run the other way, so a wallet can read a raw transaction without swapping.
The outpoint and the summed public key are hashed together into input_hash. 4 · Bind them together outpoint_L ser_P(A) input_hash = hash(outpoint_L ‖ ser_P(A)) tagged hash, tag string: BIP0352/Inputs 5bfe5321d759e01a2ac9292f0f396ff9c3d8b58d89ccb21a6922e84bb7ad0668 This is the step people skip, and it does two jobs. It makes the secret unique to this transaction, so paying the same person twice never lands on the same address. And it commits to A, so a malicious sender cannot pick a key that forces a collision.
Alice computes the shared secret from her private key and Bob's public scan key. 5 · Diffie-Hellman, 1976 secret = input_hash · a · B_scan private to Alice a printed in the address, public B_scan the point both sides will land on 028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d Alice can compute this because a is hers and B_scan is public. Nobody watching the chain can, because they hold neither private half. Fifty years old, and still the whole trick.
The shared secret and a counter produce the destination key. 6 · One key per payment tₔ = hash(ser_P(secret) ‖ k) tag: BIP0352/SharedSecret Pₔ = B_spend + tₔ·G scriptPubKey, an ordinary taproot output 5120 3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1 k counts up and never repeats, even across two labels of the same person. Every output the wallet generates must actually be broadcast. Drop one and Bob’s scan halts there and misses everything after it.
On the chain, a silent payment is indistinguishable from an ordinary taproot payment. 7 · What lands on the chain the silent payment in · P2WPKH in · P2TR out · P2TR out · P2TR change an ordinary payment in · P2WPKH in · P2TR out · P2TR out · P2TR change No marker. No OP_RETURN. Not one extra byte. Nothing on the chain says “silent payment”, so nothing can be filtered for. what Bob’s wallet needs, per eligible transaction 33 bytes · input_hash · A A full node works it out. An index server can hand it over. Doing that without telling the server which payments are yours is still unsolved.
Bob recomputes the same shared secret from public data and his own scan key. 8 · Bob does the same sum from the other side A = A₁ + A₂ · read straight off the chain the identical input_hash secret = input_hash · b_scan · A 028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d a · B_scan ≡ b_scan · A derive and compare Pₔ = B_spend + tₔ·G to spend, and only to spend d = (b_spend + tₔ) mod n One multiplication per transaction, with a key nobody else holds. No message was ever sent, and nothing was ever announced.
BIP 352 · the derivation
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 hash
input_hash = 5bfe5321d759e01a2ac9292f0f396ff9c3d8b58d89ccb21a6922e84bb7ad0668

# what an index server serves to a light client: input_hash · A
tweak      = 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.

Without input_hash two payments from the same key produce the same output address. With it they produce different ones. Without input_hash payment 1, June spends UTXO x, key A payment 2, October spends UTXO y, same key A the same P₀ one address, used twice Address reuse. The precise thing this protocol exists to prevent. With input_hash payment 1, June outpoint_L differs payment 2, October outpoint_L differs P₀ P₀′ Two unrelated addresses. Nothing on the chain joins them.
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

Three labelled addresses all share the same scan key, so an observer can tell they belong to one person B_spend m = 0 · change only · never publish sp1qqgste7k9hx0…7wvz9 m = 1 · donations sp1qqgste7k9hx0…k3m4a m = 2 · invoices sp1qqgste7k9hx0…p8x2r

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.

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 core 13.4 s
DesktopCore Ultra 9 285K, 24 core 6.7 s
Graphics cardRTX 5080, CUDA 0.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.

The underlying numbers. Scanning mainnet to block 914,000, index built from height 800,000. Benchmarks published by Frigate, the scanner Sparrow ships against.
Hardware1 day1 month1 year2 years
M1 MacBook Pro, 10 core CPU2.7 s20.0 s3 m 28 s7 m 47 s
Core Ultra 9 285K, 24 core CPU··1 m 44 s3 m 50 s
RTX 5080, CUDA··3.5 s7.7 s
Two RTX 5090, CUDA··2.1 s3.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

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.

SoftwareSendReceiveSince
Sparrow Walletyesyes2.3.0 · 2025-10-03 · receive in 2.5.0 · 2026-05-21
Cake Walletyesyesfirst merged 2024-05-31
Dana Walletyesyesexperimental
BlindBit Desktopyesyesalpha
BitBox02yes·2024-09-20
Wasabi Walletyes·2.7.2 · 2025-11-17
Nunchukyes·2026-02-20
BlueWalletyes·bundles the SilentPayments library
Electrumthird party plugin, unaudited·2026-07-26
Bitcoin Corenonothree wallet pull requests still open
BTCPay Servernonoone 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.