Silent Payments: A Case Study of Frigate for Ephemeral Client Key Scanning
Written by Sonkeng Maldini
Bitcoin is constantly evolving, and one of the recent developments attracting attention is Silent Payments.
In this post, we provide a simplified, high‑level explanation of how Silent Payments work, their advantages over existing approaches, and how they can be used in practice. We will also walk through a practical example of receiving and scanning Silent Payment outputs using Frigate and BDK.
(And yes, make sure there’s no noise around you before we start.)
What are Silent Payments?
Silent Payments are a protocol defined in BIP352 that introduce static payment addresses to Bitcoin. Compared to previous approaches, they offer several advantages:
- No on‑chain linkability
- No need for notification transactions
- Improved privacy for both sender and receiver, which is a fundamental aspect of Bitcoin
However, these benefits come with trade‑offs that we will discuss later.
Before Silent Payments, receiving payments privately required interaction between the sender and receiver for every transaction. To preserve privacy, the receiver would need to generate a fresh address and share it with the sender each time.
While effective, this approach can create poor user experience and operational challenges. For example, if you are collecting donations for a charity, you might need to run a service such as BTCPay Server to generate a new address for every donor in order to preserve privacy.
Silent Payments solve this by allowing the receiver to publish a single static address. From this address, a fresh, unique public key is derived for every transaction that sends funds to it. Although the same address is reused, only the sender and the recipient can identify the transactions associated with it.
To achieve this, the protocol relies on several cryptographic techniques, including Elliptic Curve Diffie‑Hellman (ECDH).
Elliptic Curve Diffie‑Hellman (ECDH)
This section briefly explains the ECDH cryptographic function and assumes some familiarity with ECDSA notation and concepts.
One of the key components behind Silent Payments is the ECDH key agreement protocol, which allows two parties to generate a shared secret.
Let's set up some context to better understand how the shared secret generation works:
- Alice (the sender) has a private key/public key pair:
a * G = A, whereais private key,Gthe generator point - Bob (the recipient) has a private key/public key pair:
b * G = B, wherebis private key,Gthe generator point
Now in order to generate the shared secret, Alice and Bob need to exchange their public keys: A and B. Once Alice receives Bob's public key, she then computes a secret S = a * B likewise Bob computes S = b * A.
Since the shared secret computed should be the same, it meansa * B = b * A. Substituting B by b * G we get: a * (b * G) = b * A. Given the associativity of the elliptic curve scalar multiplication, we can write: b * (a * G) = b * A , which proves the equation b * A = b * A!
Thus, both parties derive the same shared secret without revealing their private keys. This shared secret is the core mechanism used in Silent Payments.

Shared Secret Role in Locking Silent Payment Outputs
The shared secret is used to construct the public key that locks the transaction output.
Let's call the locking public key P. As defined in the BIP 352 specification, P = B + hash(a * B) * G, spotted the shared secret ? The resulting value of P is what will be put in the Taproot output of the transaction.
Notice that the locking equation has two B. Without the additional added B (means writing P = hash(a * B) * G) , coins locked by the public key (P) would still be spendable by either sender Alice (using her private key a) or recipient Bob (using his private key b).
For improved security, the protocol requires the first and the second B to be completely different values. The first one is called spend key,B_spend with its associated private key b_spend, and the second is now called scan key B_scan with it's associated private key b_scan. So the equation becomes P = B_spend + hash(a * B_scan) * G.
The reason for this is that the private key b of Bob will need to be exposed to an online device to check for incoming payments. In order to avoid any potential private key leak, the responsibilities are separated into two keys, one that's meant only for scanning and another for spending. We will see how that separation of concerns helps in the scanning section.
The combination of the spend and scan keys will now form what we call a silent payment address. An example Silent Payment address looks like this: sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv.
This address is longer than traditional Bitcoin addresses because it encodes several components:
- A human-readable part and separator
sp1 - The version
0encoded asq - Scanning and Spending public keys
- A checksum
There is much more to Silent Payments than what we have covered here. For a deeper technical explanation, the official BIP 352 specification provides further details.
How Silent Payments Compare to Other Approaches
- Using BIP 32 Extended Public Keys: By sharing the extended public key (xpub) of an entire bitcoin account, the sender can create new addresses on their own. This only solves the problem for single transaction partners at a time, though, because sharing a single extended public key with multiple entities would, again, be a major privacy compromise.
- BIP 47 introduces reusable payment codes that preserve privacy while removing the need for interaction for every transaction. However, sending funds requires a notification transaction to a notification address. This transaction includes additional data embedded in an OP_RETURN output, which adds complexity.
Scanning Silent Payment Outputs with Frigate Using bdk-sp (Experimental)
As mentioned earlier, the advantages of Silent Payments come with a trade‑off.
The receiver must scan the blockchain to detect payments sent to their address. This process can be expensive for lightweight clients, which may lack the resources to constantly scan the chain.
To mitigate this challenge, several approaches have been proposed in the Work In Progress index server specification for BIP 352. These include: remote scanner, Tweak server, and My Scanner (a personalized scanner).
A comparison between the different method from privacy to operational cost can be found here.
Frigate is an experimental Electrum server designed to test Silent Payment scanning using ephemeral client keys. It implements the remote scanner strategy.
Frigate builds on the traditional Electrum RPC protocol while introducing additional RPC methods that allow clients to request Silent Payment scanning data from the server. It uses efficient database indexing for fast queries and can optionally leverage GPU acceleration to reduce scanning time.
For this to work, the client must provide both the scan private key (b_scan) and the spend public key (B_spend).
These keys are never stored by the server. They exist only in memory during the scanning process, making them ephemeral.
For this practical we will use the bdk-sp experimental repository. It provides a wallet with support of sending and receiving SP transactions.
Setting Up the Environment
We first need to get everything up for running. Follow these links to install podman and just, which are required dependencies to make things work.
Afterwards, clone the repository:
git clone --depth 1 https://github.com/sdmg15/bdk-sp --branch feat/frigate
Once cloned head over the file frigate_playbook.sh. This file contains the necessary commands that we will need to executed in order to create and scan for outputs.
The playbook is self explanatory and organized into stages, with each stage containing several steps.
Stage 1: Setup
Let's follow the playbook and start by creating a silent payment output. The just non_nix_init command could take several minutes to complete depending, so take a cup of coffee in the meantime…
1. Install dependencies locally and setup regtest environment
- just non_nix_init
2. Check bitcoind is running on regtest
- just cli getblockchaininfo
3. Check bdk-cli wallet was created correctly
- just regtest-bdk balance
4. Check sp-cli wallet was created correctly
- just regtest-sp balance
5. Synchronize bdk-cli wallet
- just regtest-bdk sync
Stage 2: Fund bdk-cli Wallet
6. Get a new address from bdk-cli wallet
- REGTEST_ADDRESS=$(just regtest-bdk unused_address | jq -r '.address' | tr -d '\n')
7. Mine a few more blocks to fund the wallet
- just mine 1 $REGTEST_ADDRESS
8. Mine some of them to the internal wallet to confirm the bdk-cli balance
- just mine 101
9. Synchronize bdk-cli wallet
- just regtest-bdk sync
10. Check balance
- just regtest-bdk balance
Stage 3: Create a Silent Payment Output
11. Get a silent payment code from sp-cli2 wallet
- SP_CODE=$(just regtest-sp code | jq -r '.silent_payment_code' | tr -d '\n')
12. Create a transaction spending bdk-cli wallet UTXOs to a the previous silent payment code
- RAW_TX=$ (just regtest-bdk create_sp_tx --to-sp $SP_CODE:10000 --fee_rate 5 | jq -r '.raw_tx' | tr -d '\n')
- TXID=$(just regtest-bdk broadcast --tx $RAW_TX | jq -r '.txid' | tr -d '\n')
13. Mine a new block
- just mine 1
14. Once the new transaction has been mined, synchronize bdk-cli wallet again
- just regtest-bdk sync
Stage 4: Find a Silent Payment Output with Frigate
15. Now synchronize sp-cli2 wallet using frigate ephemeral scanning
- FRIGATE_HOST="127.0.0.1:57001"
- START_HEIGHT=1
- just regtest-sp scan-frigate --url $FRIGATE_HOST --start $START_HEIGHT
16. Check balance on sp-cli2 wallet
- just regtest-sp balance
17. Check balance on bdk-cli wallet
- just regtest-bdk balance
Replaying an Output of the Commands

Scanning Silent Payment Output with Frigate
If you reached this point, congratulations! You have successfully created and detected a Silent Payment output.
Conclusion
Silent Payments are an exciting development in Bitcoin’s privacy landscape. They allow users to publish static addresses while still receiving payments through unique, unlinkable outputs.
Research and development around Silent Payments are still ongoing. Developers are continuously exploring ways to balance privacy, efficiency, and usability.
If this topic interests you, consider exploring the ongoing discussions, reading the relevant BIPs, and contributing to the ecosystem.
References
1- https://github.com/bitcoin/bips/blob/master/bip-0352.mediawik
2- https://github.com/silent-payments/BIP0352-index-server-specification
3- https://blog.bitbox.swiss/en/understanding-silent-payments-part-one