avoid_reuse=true can be bypassed by using pubkey in alternate addresses #17605

issue dooglus openend this issue on November 25, 2019
  1. dooglus commented at 11:13 pm on November 25, 2019: contributor

    Once an output has been spent, the public key of output’s receiving address is made public. This allows an attacker wishing to damage a user’s privacy to generate new addresses with the same public key and send near-dust to those new addresses. Bitcoin Core (as of version 0.19.0.1) won’t recognize the dust as reusing an old address, but the attacker knows that the pair of addresses are owned by the same wallet.

    I made a new wallet, and ran getnewaddress three times to get three different addresses: one legacy, one p2sh-segwit, and one bech32:

    > getnewaddress legacy legacy           # m/0'/0'/0' : mgF6uW48rMAtBDfMuNUyYhLZ14srr19vwG
    > getnewaddress p2sh-segwit p2sh-segwit # m/0'/0'/1' : 2MtjDh43Fkot1AgA8cn7XScpvVkJYYbaMvf
    > getnewaddress bech32 bech32           # m/0'/0'/2' : bcrt1qgsr7w7qnagsk540e24sq4l3hvvu0ccq53nlzak
    

    I sent 1 BTC to each of these addresses, and then spent those 3 BTC to a throwaway address.

    I then used a 3rd party took to look up the other types of addresses for these public keys, ending up with 9 addresses (three for each of the public keys):

                 legacy                               p2sh-segwit                           bech32
                 ----------------------------------   -----------------------------------   --------------------------------------------
    m/0'/0'/0'   mgF6uW48rMAtBDfMuNUyYhLZ14srr19vwG   2Mu4jiTgDhqMsRm2AtjjF1TX6winUDUiS3P   bcrt1qqlu238za6fcpm3n0cdl3qmaxc9xvpz96y3xzhk
    m/0'/0'/1'   mhj1WrEcTvn1ZyLoxZuFPk95Yqh9P9jkKw   2MtjDh43Fkot1AgA8cn7XScpvVkJYYbaMvf   bcrt1qrqm7u7v65lz32ej5azn8ucpn973w7hsjgegs3a
    m/0'/0'/2'   mmifiHnhw1zcxQTCLmgPDaDKVvaHyTWnmA   2NFifAoVUxTvCPdR5NJ6WpNs2VbBSJNwEYc   bcrt1qgsr7w7qnagsk540e24sq4l3hvvu0ccq53nlzak
    

    I then sent coins to each of these 9 addresses to see which ones were recognized as ‘reuse’:

    > listunspent 0 0 | jq -cM '[.[] | {reused,amount,address}] | sort_by(.amount)[]'
    {"reused":true,"amount":1,"address":"mgF6uW48rMAtBDfMuNUyYhLZ14srr19vwG"}
    {"reused":false,"amount":2,"address":"2Mu4jiTgDhqMsRm2AtjjF1TX6winUDUiS3P"}
    {"reused":false,"amount":3,"address":"bcrt1qqlu238za6fcpm3n0cdl3qmaxc9xvpz96y3xzhk"}
    
    {"reused":false,"amount":4,"address":"mhj1WrEcTvn1ZyLoxZuFPk95Yqh9P9jkKw"}
    {"reused":true,"amount":5,"address":"2MtjDh43Fkot1AgA8cn7XScpvVkJYYbaMvf"}
    {"reused":false,"amount":6,"address":"bcrt1qrqm7u7v65lz32ej5azn8ucpn973w7hsjgegs3a"}
    
    {"reused":false,"amount":7,"address":"mmifiHnhw1zcxQTCLmgPDaDKVvaHyTWnmA"}
    {"reused":false,"amount":8,"address":"2NFifAoVUxTvCPdR5NJ6WpNs2VbBSJNwEYc"}
    {"reused":true,"amount":9,"address":"bcrt1qgsr7w7qnagsk540e24sq4l3hvvu0ccq53nlzak"}
    

    Only 3 of the 9 were recognized as reuse - the 3 which I had been originally given by getnewaddress, whereas for all intents and purposes all 9 are really reuse; an attacker can send dust to any of them and gain information when the dust is spent.

    Note: to get the same keys as I used in this example, you can use the following hdseed:

    > createwallet wallet_name=test blank=true avoid_reuse=true
    > sethdseed true cNonYmUoYqZ2Qyuk3McU3D65p2bMgHNH4cgmu9xdt6b2GXawiTxT
    

    Edit: To show that the pubkeys are the same for these addresses:

    $ for addr in mgF6uW48rMAtBDfMuNUyYhLZ14srr19vwG 2Mu4jiTgDhqMsRm2AtjjF1TX6winUDUiS3P bcrt1qqlu238za6fcpm3n0cdl3qmaxc9xvpz96y3xzhk \
    >             mhj1WrEcTvn1ZyLoxZuFPk95Yqh9P9jkKw 2MtjDh43Fkot1AgA8cn7XScpvVkJYYbaMvf bcrt1qrqm7u7v65lz32ej5azn8ucpn973w7hsjgegs3a \
    >             mmifiHnhw1zcxQTCLmgPDaDKVvaHyTWnmA 2NFifAoVUxTvCPdR5NJ6WpNs2VbBSJNwEYc bcrt1qgsr7w7qnagsk540e24sq4l3hvvu0ccq53nlzak
    > do
    >     bcrt getaddressinfo $addr | jq -crM '{pubkey,hdkeypath,address}'
    > done
    {"pubkey":"02dc7bd5438c460e74faf57a63c98937bf381eff623977fce9ec8c099434087047","hdkeypath":"m/0'/0'/0'","address":"mgF6uW48rMAtBDfMuNUyYhLZ14srr19vwG"}
    {"pubkey":"02dc7bd5438c460e74faf57a63c98937bf381eff623977fce9ec8c099434087047","hdkeypath":"m/0'/0'/0'","address":"2Mu4jiTgDhqMsRm2AtjjF1TX6winUDUiS3P"}
    {"pubkey":"02dc7bd5438c460e74faf57a63c98937bf381eff623977fce9ec8c099434087047","hdkeypath":"m/0'/0'/0'","address":"bcrt1qqlu238za6fcpm3n0cdl3qmaxc9xvpz96y3xzhk"}
    
    {"pubkey":"024cd5841775e7dc334d3739ef52fc2a7e01ef8eaaa1fc503803711a0602107d54","hdkeypath":"m/0'/0'/1'","address":"mhj1WrEcTvn1ZyLoxZuFPk95Yqh9P9jkKw"}
    {"pubkey":"024cd5841775e7dc334d3739ef52fc2a7e01ef8eaaa1fc503803711a0602107d54","hdkeypath":"m/0'/0'/1'","address":"2MtjDh43Fkot1AgA8cn7XScpvVkJYYbaMvf"}
    {"pubkey":"024cd5841775e7dc334d3739ef52fc2a7e01ef8eaaa1fc503803711a0602107d54","hdkeypath":"m/0'/0'/1'","address":"bcrt1qrqm7u7v65lz32ej5azn8ucpn973w7hsjgegs3a"}
    
    {"pubkey":"028c4e68ac42a9d0bc7c11591768b8bdbd25e5c7b666e96d452c9756b0d1acd28b","hdkeypath":"m/0'/0'/2'","address":"mmifiHnhw1zcxQTCLmgPDaDKVvaHyTWnmA"}
    {"pubkey":"028c4e68ac42a9d0bc7c11591768b8bdbd25e5c7b666e96d452c9756b0d1acd28b","hdkeypath":"m/0'/0'/2'","address":"2NFifAoVUxTvCPdR5NJ6WpNs2VbBSJNwEYc"}
    {"pubkey":"028c4e68ac42a9d0bc7c11591768b8bdbd25e5c7b666e96d452c9756b0d1acd28b","hdkeypath":"m/0'/0'/2'","address":"bcrt1qgsr7w7qnagsk540e24sq4l3hvvu0ccq53nlzak"}
  2. dooglus added the label Bug on Nov 25, 2019
  3. instagibbs commented at 3:35 pm on November 27, 2019: member
    Hmm this is pretty bad. I think at least after #13002 we’re down to only 3 possible addresses that can be dusted. Prior to that you could just continuously dust multisig templates where Core owns all the private keys.
  4. instagibbs commented at 3:59 pm on November 27, 2019: member
    There are probably other cases dealing with people dusting an imported multisig address with shared keys, but we can deal with the immediate leak now and plug this gap with smarter behavior in the future.
  5. sipa commented at 5:01 pm on November 27, 2019: member
    With descriptor wallets this problem will go away, as we’ll just stop treating these modified-address-type addresses as ours.
  6. laanwj added the label Wallet on Dec 12, 2019
  7. meshcollider referenced this in commit bcb4cdcca3 on Jan 7, 2020
  8. instagibbs commented at 9:34 pm on January 7, 2020: member
    this issue should be fixed in master
  9. fanquake closed this on Jan 7, 2020

  10. sidhujag referenced this in commit 69d7ae3cc0 on Jan 8, 2020
  11. sidhujag referenced this in commit 7bb63d3ef8 on Nov 10, 2020
  12. DrahtBot locked this on Feb 15, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-03 13:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me