Progress pill
Understanding the challenges of other advanced confidentiality techniques

Silent Payments

Privacy on Bitcoin

Silent Payments

  • Why not move the notification?
  • A few concepts to understand
  • Naive derivation of a Silent Payments public key
  • How do I create multiple outputs?
  • How to avoid address reuse?
  • Tweaking public keys into inputs
  • Separate expense and scan keys
  • Using SP addresses with a label
  • How do I build a Silent Payments address?
  • How do I use Silent Payments?
BIP47 has been widely criticized for its on-chain inefficiency. As explained in the previous chapter, a notification transaction must be carried out for each new recipient. This constraint becomes negligible if we plan to establish a sustainable payment channel with this recipient. Indeed, a single notification transaction paves the way for an almost infinite number of subsequent BIP47 payments.
However, in certain situations, the notification transaction can be an obstacle for the user. Let's take the example of a one-off donation to a recipient: with a classic Bitcoin address, a single transaction is enough to complete the donation. But with BIP47, two transactions are required: one for the notification and another for the actual payment. When demand for block space is low and transaction fees are also low, this extra step is typically not a problem. However, in times of congestion, transaction fees can become exorbitant for a single payment, potentially doubling the cost to the user compared to a standard Bitcoin transaction, which may prove unacceptable to the user.
For situations where the user plans to make only a few payments to a static identifier, other solutions have been developed. These include Silent Payments, described in BIP352. This protocol enables the use of a static identifier to receive payments without address reuse and without requiring notification transactions. Let's examine how this protocol works.

To fully understand this chapter, it is essential to master the workings of ECDH (Elliptic Curve Diffie-Hellman) and cryptographic key derivation in an HD wallet. These concepts were covered in detail in the previous chapter on BIP47. I won't repeat them here. If you are not yet familiar with these concepts, I recommend that you consult the previous chapter before continuing with this one. I won't go back over the risks associated with the reuse of receiving addresses, nor the importance of having a unique identifier for receiving payments. I'll just mention a few points that I'd like to make here

Why not move the notification?

As discussed in the BIP47 chapter, the notification transaction has two main functions:
  • It notifies the recipient.
  • It transmits the sender's payment code.
One might naively think that this notification process could be carried out off-chain. In theory, it's perfectly feasible: all the recipient would have to do is indicate a means of communication to receive the BIP47 payment codes from the senders. However, there are two major problems with this approach:
  • Firstly, it would move the code transmission process to another communication protocol. Problems relating to the cost and confidentiality of the exchange would remain, but would simply be transferred to this new protocol. In terms of confidentiality, this could also create a link between a user's identity and on-chain activity, which is what we seek to avoid by performing the notification directly on the blockchain. Furthermore, making the notification outside the blockchain would introduce risks of censorship (such as blocking funds) that do not exist on Bitcoin.
  • Secondly, this would pose a recovery problem. With BIP47, the recipient must know the payment codes of the senders in order to access the funds. This is true upon receipt, but also in the event that funds are recovered via the seed if the wallet is lost. With on-chain notifications, this risk is avoided, as the user can retrieve and decrypt notification transactions simply by knowing their seed. However, if the notification is made outside the blockchain, the user would have to maintain a dynamic backup of all payment codes received, which is impractical for the average user.
All these constraints make the use of on-chain notification essential for BIP47. However, Silent Payments seeks to avoid this on-chain notification step precisely because of its cost. The solution adopted is therefore not to move the notification, but to eliminate it entirely. To achieve this, a compromise has to be accepted: scanning. Unlike BIP47, where the user knows exactly where to find their funds thanks to notification transactions, with Silent Payments, the user must examine all existing Bitcoin transactions to detect any payments intended for them. To reduce this operational burden, the Silent Payments search is limited only to transactions likely to contain such payments, i.e., those with at least one Taproot P2TR output. The scan also focuses exclusively on transactions from the wallet creation date (there's no need to scan transactions dating back to 2009 if the wallet was created in 2024).
As you can see, BIP47 and Silent Payments, although aimed at a similar objective, involve different trade-offs and therefore actually meet distinct use cases. For one-time payments, such as donations, Silent Payments are more suitable due to their lower cost. On the other hand, for regular transactions to the same recipient, as in the case of exchange platforms or mining pools, BIP47 may be a preferred option.
Let's examine the technical operation of Silent Payments to gain a deeper understanding of what's at stake. To achieve this, I suggest we adopt the same approach as outlined in the BIP352 explanatory document. We'll gradually break down the calculations to be carried out, element by element, justifying each new addition.

A few concepts to understand

Before getting started, it's essential to note that Silent Payments rely exclusively on the use of P2TR (Pay to Taproot) script types. Unlike BIP47, it is not necessary to derive receiving addresses from child public keys by hashing. In the P2TR standard, the tweaked public key is used directly and unencrypted in the address. So a Taproot receive address is essentially a public key with some metadata. This tweaked public key is the aggregation of two other public keys: one enabling direct, traditional spending via a simple signature, and the other representing the Merkle root of the MAST, which authorizes spending subject to the satisfaction of one of the conditions potentially inscribed in the Merkle tree.
There are two main reasons for the decision to limit Silent Payments exclusively to Taproot:
  • Firstly, it considerably facilitates implementation and future upgrades in wallet software, since only one standard needs to be respected;
  • Secondly, this approach helps to improve users' anonset by encouraging them not to divide themselves between different types of scripts, which generate distinct wallet fingerprints in chain analysis (for more information on this concept, please refer to chapter 4 of part 2).

Naive derivation of a Silent Payments public key

Let's start with a simple example to understand how Silent Payments (SPs) work. Let's take Alice and Bob, two Bitcoin users. Alice wishes to send Bitcoins to Bob on a blank receiving address. There are three objectives to this process:
  • Alice must be able to generate a blank address.
  • Bob must be able to identify a payment sent to this specific address.
  • Bob needs to be able to obtain the private key associated with this address in order to spend his funds.
Alice has a UTXO in her secure Bitcoin wallet with the following key pair:
  • : the private key;
  • : the public key ()
Bob has an SP address, which he has published on the Internet:
  • : the private key;
  • : the public key ()
By retrieving Bob's address, Alice is able to calculate a new blank address that belongs to Bob using ECDH. Let's call this address :
In this equation, Alice has simply calculated the scalar product of her private key, , and Bob's public key, . She has passed this result into a hash function known to everyone. The resulting value is then multiplied scalarly by the generating point of the elliptic curve secp256k1. Finally, Alice adds the resulting point to Bob's public key . Once Alice has this address , she uses it as an output in a transaction, i.e., she sends bitcoins to it.
In the context of Silent Payments, the "hash" function corresponds to a SHA256 hash function specifically tagged with BIP0352/SharedSecret, which ensures that the hashes generated are unique to this protocol and cannot be reused in other contexts, while offering additional protection against the reuse of nonces in signatures. This standard corresponds to that specified in BIP340 for Schnorr signatures on secp256k1. Thanks to the properties of the elliptic curve on which ECDH is based, we know that:
Bob will therefore be able to calculate the receiving address to which Alice has sent the bitcoins. To do this, he monitors all Bitcoin transactions that meet the Silent Payments criteria and applies the following calculation to each of them to see if the payment is addressed to him (scanning):
When he scans Alice's transaction, he realizes that equals . He therefore knows that the payment is addressed to her:
From here, Bob will be able to calculate the private key , which allows the address to be spent:
As you can see, to calculate this private key , you must have the private key . Only Bob has this private key . He will therefore be the only one able to spend the bitcoins sent to his Silent Payments address.
Legend:
  • : The public key/static address published by Bob
  • : Bob's private key
  • : Alice's UTXO public key used as transaction input
  • : Alice's private key
  • : The generating point of the elliptic curve secp256k1
  • : The SHA256 hash function tagged with BIP0352/SharedSecret
  • : The ECDH common secret
  • : The public key/unique address for payment to Bob
Here's a rather naive initial approach to using Bob's static address, noted , to derive a unique address to send bitcoins to. However, this method is too simplistic and has several flaws that need to be corrected. The first problem is that, in this scheme, Alice cannot create multiple outputs to Bob within the same transaction.

How do I create multiple outputs?

In the example from the previous section, Alice creates a single output that will be sent to Bob at his unique address, . With the same input selected, it is impossible for Alice to create two separate blank addresses for Bob, as the method used would always lead to the same result for , i.e., the same address. However, there may be many situations where Alice wishes to divide her payment to Bob into several smaller amounts, thus creating several UTXOs. It is therefore necessary to find a method of achieving this.
To achieve this, we will slightly modify the calculation Alice performs to derive , so that she can generate two distinct addresses for Bob, namely and .
To modify the calculation and obtain 2 different addresses, simply add an integer that modifies the result. Thus, Alice will add to her calculation to obtain the address and to obtain the address . Let's call this integer :
The calculation process remains unchanged from the previous method, except that this time Alice will concatenate with before proceeding with the hash. You then simply modify to obtain a new address belonging to Bob. For example:
When Bob scans the blockchain for Silent Payments intended for him, he starts by using for address . If he doesn't find any payments on , he concludes that this transaction contains no Silent Payments intended for him, and abandons the scan. However, if is valid and contains a payment for him, he continues with in the same transaction to check whether Alice has made a second payment. If turns out to be invalid, it stops searching for this transaction; otherwise, it continues testing successive values:
Since Bob stops immediately at if doesn't work, using this integer adds almost no additional operational load on Bob for the transaction scanning stage.
Bob can then calculate the private keys in the same way:
Legend:
  • : The public key/static address published by Bob
  • : Bob's private key
  • : Alice's UTXO public key used as transaction input
  • : Alice's private key
  • : The generating point of the elliptic curve secp256k1
  • : The SHA256 hash function tagged with BIP0352/SharedSecret
  • : The first common secret ECDH
  • : The second ECDH common secret
  • : The first public key / unique address for payment to Bob
  • : The second public key / unique address for payment to Bob
With this method, we're starting to get a nice protocol, but there are still a few challenges to overcome, not least the prevention of address reuse.

How to avoid address reuse?

As we saw in the previous sections, Alice uses the key pair that secures her UTXO, which she will spend to calculate the ECDH shared secret with Bob. This secret enables her to derive the unique address . However, the key pair (, ) used by Alice can secure several UTXOs if she has reused this address several times. If Alice makes two payments to Bob's static address using two UTXOs secured by the same key , this would result in address reuse for Bob.
Address reuse is a poor practice in terms of user confidentiality. To find out why, I recommend reviewing the first parts of this course. Indeed, since the unique address is derived from and , well, if Alice derives a second address for a second payment to , with the same key , she'll end up on exactly the same address . To avoid this risk and prevent address reuse within Silent Payments, we'll need to modify our calculations a little.
What we want is for each UTXO consumed by Alice as input to a payment to give a unique address on Bob's side, even if several UTXOs are secured by the same key pair. So all we need to do is add a reference to the UTXO when calculating the unique address . This reference will simply be the hash of the UTXO consumed as input:
And Alice will add this reference to the input to her calculation of the unique address :
When scanning, Bob can also add , since all he has to do is observe the transaction to deduce :
When he finds a valid , he can calculate the corresponding private key:
Legend:
  • : The public key/static address published by Bob
  • : Bob's private key
  • : Alice's UTXO public key used as transaction input
  • : Alice's private key
  • : UTXO hash used as input
  • : The generating point of the elliptic curve secp256k1
  • : The SHA256 hash function tagged with BIP0352/SharedSecret
  • : The first ECDH common secret
  • : The first public key / unique address for payment to Bob
For the moment, our calculations assume that Alice uses a single input for her transaction. However, she should be able to use several inputs. Consequently, on Bob's side, for each transaction involving several inputs, he should theoretically calculate the ECDH for each input to determine whether a payment is intended for him. This method is not satisfactory, so we need to find a solution to reduce the workload!

Tweaking public keys into inputs

To solve this problem, instead of using the key pair securing a specific input on Alice's side, we'll use the sum of all the key pairs used in the transaction's inputs. This sum will then be considered as a new key pair. This technique is known as "tweaking".
For example, let's imagine that Alice's transaction has 3 inputs, each secured with a different key pair:
  • is used to secure input #0;
  • is used to secure input #1;
  • secures input #2.
Following the method previously described, Alice would have to choose a single key pair from among , , and to calculate the ECDH secret and generate the single payment address from Bob's static address . However, this approach requires Bob to test each possibility sequentially, starting with , then , and so on, until he identifies a pair that generates a valid address. This process requires Bob to run the ECDH calculation on all inputs to all transactions, which considerably increases the operational load of scanning.
To avoid this, we'll ask Alice to calculate using the sum of all input keys. Using our example, the tweaked private key would be calculated as follows:
In the same way, Alice and Bob can calculate the tweaked public key:
With this method, Bob only needs to calculate the sum of the transaction's public keys, then calculate the ECDH secret from alone, which greatly reduces the number of calculations required for the scanning stage.
However, remember the previous section. We had added the hash to our calculation, which is used as a nonce to avoid address reuse:
But if you have several inputs in a transaction, you need to be able to determine which is chosen in this calculation. According to BIP352, the selection criterion to be used is to choose the smallest lexicographically, which means selecting the UTXO that appears first in alphabetical order. This method standardizes the UTXO to be chosen in each transaction. For example, if this lexicographically smallest is , the calculation of will be:
The calculations then remain identical to those presented in the previous section, except that the private key and its corresponding public key are no longer a pair used to secure a single input, but now represent the tweak for all key pairs in inputs.

Separate expense and scan keys

For the moment, we've referred to the Silent Payment static address as a unique public key. Remember, it's this public key that Alice uses to create the shared secret ECDH, which in turn calculates the unique payment address . Bob uses this public key and the corresponding private key for the scanning stage. However, he will also use the private key to calculate the private key , which enables spending from the address .
The disadvantage of this method is that the private key (which is used to calculate all the private keys of those addresses that have received Silent Payments) is also used by Bob to scan the transactions. This step requires the key to be available on internet-connected wallet software, which exposes it to a greater risk of theft than keeping it on a cold wallet. Ideally, it would be beneficial to be able to take advantage of Silent Payments while keeping the private key, which controls access to all other private keys, secure on a hardware wallet. Fortunately, the protocol has been adapted to accommodate this.
To do this, BIP352 requires the receiver to use 2 different pairs of keys:
  • : to calculate the private keys of unique payment addresses;
  • : to find unique payment addresses.
In this way, Bob can keep the private key on a hardware wallet and use the private key on online software to find his Silent Payments, without revealing . On the other hand, the public keys and are both publicly revealed, since they are located in Bob's static address :
To calculate a unique payment address belonging to Bob, Alice will now perform the following calculation:
To find the payments addressed to him, Bob will perform the following calculation:
As you can see, so far Bob hasn't needed to use , which is on his hardware wallet. When he wants to spend the UTXO related to , he can do the following calculation to find the private key :
Legend:
  • : Bob's public scan key (static address)
  • : Bob's private scan key
  • : Bob's public spending key (static address)
  • : Bob's private spending key
  • : Sum of public key inputs (tweak)
  • : The private key corresponding to the tweaked public key
  • : The hash of the smallest UTXO (lexicographically) used as input
  • : The generating point of the elliptic curve secp256k1
  • : The SHA256 hash function tagged with BIP0352/SharedSecret
  • : The first common secret ECDH
  • : The first public key / unique address for payment to Bob

Using SP addresses with a label

Bob therefore has a static address for Silent Payments, such as:
The problem with this method is that it doesn't allow you to segregate the different payments sent to this address. For example, if Bob has two different customers for his business and wants to differentiate payments to each, he'll need two different static addresses. A naive solution, with the current approach, would be for Bob to create two separate wallets, each with its own static address, or even to establish two different static addresses within the same wallet. However, this solution requires scanning the entire blockchain twice (once for each address) in order to detect payments destined for each address. This double scanning unreasonably increases Bob's operational load.
To solve this problem, BIP352 utilizes a label system that enables different static addresses without unreasonably increasing the workload of identifying Silent Payments on the blockchain. To do this, we add an integer to the public spending key . This integer can take the value of for the first static address, then for the second, and so on. The spending keys will now be called and will be constructed in this way:
For example, for the first expense key with the label :
The static address published by Bob will now consist of and . For example, the first static address with the label will be:
We only start from label 1 because label 0 is reserved for the change. Alice, on her side, will derive the single payment address in the same way as before, but using the new instead of :
In reality, Alice doesn't even necessarily know that Bob has a labeled address, as she's simply using the second part of the static address he provided, and in this case, it's the value rather than .
To scan payments, Bob will always use the value of his initial static address with in this way:
Then, he simply subtracts the value he finds for from each output one by one. He then checks whether one of the results of these subtractions matches the value of one of the labels he's using on his wallet. If, for example, output #4 matches the label, this means that this output is a Silent Payment associated with its statically labeled address :
It works because:
Thanks to this method, Bob can use a multitude of static addresses (, , ...), all derived from his basic static address (), in order to keep usage separate.
Please note, however, that this separation of static addresses is only valid from a personal wallet management perspective, but does not separate identities. Since they all have the same , it's very easy to associate all static addresses together and deduce that they belong to a single entity.
Legend:
  • : Bob's public scan key (static address)
  • : Bob's private scan key
  • : Bob's public spending key (initial address)
  • : Bob's public spending key labeled (static address)
  • : Bob's private spending key labelled
  • : Sum of public key inputs (tweak)
  • : The private key corresponding to the tweaked public key
  • : The hash of the smallest UTXO (lexicographically) used as input
  • : The generating point of the elliptic curve secp256k1
  • : The SHA256 hash function tagged with BIP0352/SharedSecret
  • : The first ECDH common secret
  • : The first public key / unique address for payment to Bob
  • : The private key of the first unique payment address to Bob
  • : The hash of the scan private key with the label

How do I build a Silent Payments address?

To build an address dedicated to Silent Payments, you first need to derive 2 key pairs from your Bitcoin HD wallet:
  • The pair , to search for payments addressed to us;
  • The pair , to spend the bitcoins we've received.
These pairs are derived using the following paths (Bitcoin Mainnet):
scan: m / 352' / 0' / 0' / 1' / 0 spend: m / 352' / 0' / 0' / 0' / 0
Once we have these 2 pairs of keys, we simply concatenate them (end-to-end) to create the static address payload:
If we want to use labels, we'll replace with :
With label :
Once we have this payload, we add the HRP (Human-Readable Part) sp and the version q (= version 0). We also add a checksum and format the address as bech32m.
For example, here is my Silent Payments static address:
sp1qqvhjvsq2vz8zwrw372vuzle7472zup2ql3pz64yn5cpkw5ngv2n6jq4nl8cgm6zmu48yk3eq33ryc7aam6jrvrg0d0uuyzecfhx2wgsumcurv77e
An important point concerning static addresses, which you may have grasped in the previous sections, is that these addresses are not visible in Bitcoin transactions. Only the payment addresses used in outputs appear on the blockchain in the standard Taproot format. So, from the outside, it's impossible to distinguish a transaction involving Silent Payment from an ordinary transaction using P2TR outputs.
As with BIP47, it is impossible to establish a connection between a static address and a payment address derived from . Indeed, even if Eve, a potential attacker, attempts to scan the blockchain with Bob's static address, she won't be able to perform the calculations required to determine . To do so, she would need either Bob's private key , or the sender's private keys , but both are, of course, private. It is therefore possible to explicitly link one's static address with a form of personal identity, for example, by publishing one's static address on an X (Twitter) profile.

How do I use Silent Payments?

The Silent Payments proposal is relatively recent and has only been implemented by a limited number of wallets at present. To my knowledge, there are only 3 software products that support them:
We'll soon provide you with a detailed tutorial on how to set up your own Silent Payments static address.
Since this feature is new, we recommend exercising caution and avoiding the use of Silent Payments for large amounts on the mainnet.
To create this chapter on Silent Payments, I used the Silent Payments explanation site and the BIP352 explanation document.
Quiz
Quiz1/5
What is the name of the cryptographic algorithm used in Silent Payments to establish a shared secret between the receiver and the payer?