Follow-up: a transaction demonstrating the discussed worst-case scanning
attack with 23230 outputs is now available on Signet (block height 297894) [1]:

https://mempool.space/signet/block/00000002f010f4f0dcc89bb3cf951e70d59d8be04fa6fd2d281842c0ba6e02a2
https://mempool.space/signet/tx/e429ec8858d0b34d7e05f1ce178ada4ae197fa7186830613a304c59f9687a80e

Wallets can exercise the effect of a targeted attack by scanning this block
with the following key and label material:

Scan secret key:   00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
Scan public key:   02c2a4c3969a1acfd0a67f8881a894f0db3b36f7f1dde0b053b988bf7cff325f6c
Spend secret key:  ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100
Spend public key:  0398dc4ade30b8aee66db06be9d22543df8bc7b4ea8f177dcb2124d8789c8b97d3
Label tweak (m=0): adecfc875af28554f2588be4f25cbb68b33a0e015cea5f67f954ea9b901848c1
Label (m=0):       03c848bb6729345caa616ec32ca54eeeac14f3c77cedcfae66ecdda5b5a06ad883
Labeled spend key: 03eff186a9a7c8e40b484c7fa4865e0bf52f9a10d09e1f95ce36ad6c241ded54e5

All 23230 outputs were created with the same labeled address as recipient:
sp1qqtp2fsukngdvl59x07ygr2y57rdnkdhh78w7pvznhxyt7l8lxf0kcql07xr2nf7gus95snrl5jr9uzl497dpp5y7r72uud4ddsjpmm25u5re4lah

Note that as per the latest BIP-352 protocol change [2], only 2323 of these outputs
(created with k values in the range [0..2322] inclusive) are valid.
As a recap, the attack is only relevant for users following the "BIP approach"
of scanning. Wallets using the "LabelSet approach" are very likely not affected
(with or without the protocol change) [3].

I've hacked together a small demo that uses libbitcoinkernel and the secp256k1
silentpayments module [4] to scan this block (assuming that an unpruned signet
datadir sits in ~/.bitcoin/signet), with and without the K_max protocol limit to
show the difference:

$ git clone https://github.com/theStack/bip352-signet-scan-worstcase
$ cd bip352-signet-scan-worstcase
$ ./build_and_run.sh
[ ... ]
Scanning 1-in-23230-out tx e429ec8858d0b34d7e05f1ce178ada4ae197fa7186830613a304c59f9687a80e...
-> Uncapped K [worst-case order]: scanning took 165.186 seconds (23230 outputs found)
-> Uncapped K [shuffled outputs]: scanning took 165.852 seconds (23230 outputs found)
-> K_max=2323 [worst-case order]: scanning took 31.404 seconds (2323 outputs found)
-> K_max=2323 [shuffled outputs]: scanning took 16.930 seconds (2323 outputs found)

Note that shuffling outputs doesn't improve anything in the uncapped case, as
the secp256k1 implementation currently doesn't skip found outputs to keep it
simple -- with the K_max limit, it wouldn't improve the worst-case performance
noticeably.

For anyone wondering, the demo code is currently not suitable for scanning SP
transactions in general, as it assumes a single input and is only able to cope
with P2TR inputs. It might be a workable starting point for a general BIP-352
scanning tool using libbitcoinkernel and libsecp256k1, if anyone is interested
in working on that.

Best,
Sebastian

[1] thanks to AJ Towns for mining this block; as this is a non-standard tx
exceeding 100 kvB, offband communication was necessary to make this happen
[2] https://github.com/bitcoin/bips/pull/2106
[3] see discussion https://github.com/bitcoin-core/secp256k1/issues/1799#issuecomment-3773155788 ff.
[4] PR #1765: https://github.com/bitcoin-core/secp256k1/pull/1765

On Wednesday, March 4, 2026 at 11:38:06 AM UTC+1 Sebastian Falbesoner wrote:
Update: the proposed BIP-352 protocol change [1] was merged, setting K_max = 2323.
This limit was chosen intentionally, as it represents the maximum number of taproot
outputs that can fit within a <= 100 kvB transaction with the smallest Silent Payments
eligible input (a taproot key-path spend) [2].

Consequently, any transaction that adheres to the current transaction size
policy rule [3] is guaranteed to also comply with the K_max protocol limit. It
is therefore extremely unlikely that any wallet would ever encounter this limit
in practice, as such a transaction would not propagate on the network.

Thanks to everyone involved in proposing, discussing and reviewing this change.

The secp256k1 silentpayments module PR [4] will be updated and taken out of
draft state shortly.

Best,
Sebastian

[1] https://github.com/bitcoin/bips/pull/2106
[2] a 1-in-2323-out P2TR transaction has a vsize of 99959 vbytes, see e.g. https://jlopp.github.io/bitcoin-transaction-size-calculator/ or https://bitcoinops.org/en/tools/calc-size/ (note that the latter calculator doesn't account the two extra bytes needed for the output-count compactSize encoding); adding one more taproot output (taking 43) vbytes would result in 100002 vbytes
[3] `MAX_STANDARD_TX_WEIGHT` in Bitcoin Core (expressed in WUs): https://github.com/bitcoin/bitcoin/blob/2702711c3a54b2ba9ae3781b61c90d28ee951de6/src/policy/policy.cpp#L110-L114
[4] https://github.com/bitcoin-core/secp256k1/pull/1765

On Friday, February 20, 2026 at 12:36:08 AM UTC+1 Sebastian Falbesoner wrote:
Thanks for all the feedback left on the secp256k1 issue [1].

As no objections were raised to the proposed K_max protocol change, I've opened a corresponding PR in the BIPs repository, where the discussion can be continued:
https://github.com/bitcoin/bips/pull/2106

Best, Sebastian

[1] https://github.com/bitcoin-core/secp256k1/issues/1799#issuecomment-3842046237 ff.
On Wednesday, February 4, 2026 at 6:21:09 PM UTC+1 Sebastian Falbesoner wrote:
Hi list,

In the course of working on a Silent Payments module for libsecp256k1 [1], we

discovered that the scanning approach suggested in BIP-352 [2] suffers from

very poor performance for adversarial transactions [3].


One more recent proposal to mitigate this issue is by introducing a "K_max"

protocol limit. This effectively limits the number of per-group recipients

within a single transaction, i.e. the number of recipients sharing the same

scan public key. In theory this is a backwards incompatible protocol change,

in practice we believe that none of the existing SP wallets would be affected,

for a reasonably high K_max (the example value used is K_max=1000, but this

can be seen as a placeholder).


See the following BIP change draft for more details and motivation:

https://github.com/theStack/bips/commit/961d1442139ceecd6c0cc5775ef911d69aabed4c


The discussion is on-going at the following issue:

https://github.com/bitcoin-core/secp256k1/issues/1799 [4]


If you have any concerns or feedback for this change, either for currently

existing wallets or potential future use-cases that you could think of, please

comment there. Most SP wallet developers that we are aware of have already been

pinged on the issue. We are posting this here to reach a wider audience and to

provide an alternative opportunity to comment, in case anyone doesn't want to

use GitHub.


Best,
Sebastian

[1] https://github.com/bitcoin-core/secp256k1/pull/1765

[2] https://github.com/bitcoin/bips/blob/5d0f70a5cf4cfc429267cd6cc246ba3bcb949cb3/bip-0352.mediawiki?plain=1#L330

[3] https://github.com/bitcoin-core/secp256k1/pull/1698#pullrequestreview-3341766084

[4] https://github.com/bitcoin-core/secp256k1/issues/1799#issuecomment-3842046237 ff. in particular

--
You received this message because you are subscribed to the Google Groups "Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bitcoindev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/cf64109b-4d78-4515-a68e-d427243a105cn%40googlegroups.com.