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/00000002f010f4f0dcc89bb3cf951e70d59d8be04fa6fd2d281842c0ba6e02a2https://mempool.space/signet/tx/e429ec8858d0b34d7e05f1ce178ada4ae197fa7186830613a304c59f9687a80eWallets 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