bitcoin-keeper icon indicating copy to clipboard operation
bitcoin-keeper copied to clipboard

Missing fields in "output" of PSBT for signer validation

Open jdlcdl opened this issue 6 months ago • 1 comments

I'm writing today on behalf of another krux developer who had trouble validating self-spends as belonging to the signing wallet. Familiar with how this works in both krux and seedsigner... but not having used BitcoinKeeper to prepare any of the following evidence, I'm writing to explain my understanding of what appears to be missing fields in a PSBT that are normally used to help a hardware signer in validating addresses owned by the wallet.

Despite this drawback, it is my understanding that bitcoin-keeper is already a supporting watch-only wallet coordinator for working with seedsigner. I believe it's soon the same case for krux, so I wanted to make sure this issue is known for future improvement.


example 1

A singlesig NativeSegwit wallet sending to receive address #1

Key info: bip39 mnemonic ("zoo " * 11 + "daring") w/o passphrase, on testnet4

fingerprint: e6502299

descriptor: wpkh([e6502299/84h/1h/0h]tpubDDLe6nRX2exHwxgThJFNvkjSUM2kLyeZAZNsgmNvmAcwDN62nov6mNB552CVm8p3SD99z4EnchMw9kzmKXgrcXXwp32VBmwmaWY7p2t7fru/<0;1>/*)

unsigned PSBT: cHNidP8BAHECAAAAAZA495zFwB0NACM6jIYbwmAWaNq8novMAWt1rCpyJGd9AgAAAAD+////AmAJAAAAAAAAFgAUfI4igxhLR0Kk5Ce6dlmU0OkKzZyLbwAAAAAAABYAFHH968KnOi0K4zWBEIIgSPmWuhf3PlsBAAABAR98eQAAAAAAABYAFEkxVEITvDpKgQXjIwqtAXxy+P3gIgYCwlC/8Y6pcWMmv/BocRdbzmPVFUKtLTnycjn0stMA8VoY5lAimVQAAIABAACAAAAAgAEAAAAEAAAAAAAiAgO3wuE+b++9T0WWjfnEZrZVAOBbuncEoc/zcs3M671FpBjmUCKZVAAAgAEAAIAAAACAAQAAAAUAAAAA

The Issue

This PSBT was prepared to pay the 2nd receive address within the same wallet (receive address #1), however the outputs array in the PSBT is missing a "bip32_derivs" dictionary that would describe the "pubkey", "master_fingerprint" and "path" for quickly verifying that this PSBT is truly a self-spend to the same wallet. What is odd, is that the change coming back into the wallet DOES have these fields. Hardware signers could of course brute-force their addresses to know that this is a self-transfer, but instead they're looking for these hints in the PSBT "outputs" for direct verification.

Looking only at the "outputs" fields, via core's bitcoin-cli decodepsbt for above:

  "outputs": [
    {
    },
    {
      "bip32_derivs": [
        {
          "pubkey": "03b7c2e13e6fefbd4f45968df9c466b65500e05bba7704a1cff372cdccebbd45a4",
          "master_fingerprint": "e6502299",
          "path": "m/84h/1h/0h/1/5"
        }
      ]
    }
  ],

Above, we can see that the first output's array is empty, leaving no convenient info for a signer to validate. However, we do see the 6th change address can be conveniently validated.

Correcting the above PSBT via bitcoin-cli descriptorprocesspsbt results in the following:

corrected unsigned PSBT: cHNidP8BAHECAAAAAZA495zFwB0NACM6jIYbwmAWaNq8novMAWt1rCpyJGd9AgAAAAD+////AmAJAAAAAAAAFgAUfI4igxhLR0Kk5Ce6dlmU0OkKzZyLbwAAAAAAABYAFHH968KnOi0K4zWBEIIgSPmWuhf3PlsBAAABAR98eQAAAAAAABYAFEkxVEITvDpKgQXjIwqtAXxy+P3gIgYCwlC/8Y6pcWMmv/BocRdbzmPVFUKtLTnycjn0stMA8VoY5lAimVQAAIABAACAAAAAgAEAAAAEAAAAACICA2BnHWGpoYKHSb2v7UN8BG8Wr+ntt4WGBH3q6BhCtF/nGOZQIplUAACAAQAAgAAAAIAAAAAAAQAAAAAiAgO3wuE+b++9T0WWjfnEZrZVAOBbuncEoc/zcs3M671FpBjmUCKZVAAAgAEAAIAAAACAAQAAAAUAAAAA

Again, focusing on the "outputs" fields, we can see what a signer would be expecting to validate both a self-transfer output as well as change:

  "outputs": [
    {
      "bip32_derivs": [
        {
          "pubkey": "0360671d61a9a1828749bdafed437c046f16afe9edb78586047deae81842b45fe7",
          "master_fingerprint": "e6502299",
          "path": "m/84h/1h/0h/0/1"
        }
      ]
    },
    {
      "bip32_derivs": [
        {
          "pubkey": "03b7c2e13e6fefbd4f45968df9c466b65500e05bba7704a1cff372cdccebbd45a4",
          "master_fingerprint": "e6502299",
          "path": "m/84h/1h/0h/1/5"
        }
      ]
    }

Similar is the case for multisig

example 2

A 2-of-2 multisig NativeSegwit wallet paying 2 external addresses, 1 internal receive address and 1 change address.

fingerprints: e0c595c5, e6502299 (from above key).

output descriptor: wsh(sortedmulti(2,[E0C595C5/48h/1h/0h/2h]tpubDErwirr9PdyV44W8DuEC5X8Usm58H6ocj8nbScFmRb7wvNntzTRjWdakBS44i6wNMoiRxUKpYXfaX9swGCYb13tDESNEeUJmFqMzZ513Cgh/<0;1>/*,[E6502299/48h/1h/0h/2h]tpubDEqC2WKtUJWug5JWAE5NY87Jt6coKNfdvbyhEp1WAf6bAcKuqJHcoQktJPDzmkEKzqgsqezRAcPdHixRXv4bZEWCDtR8pLnoJPYSyAwhqTW/<0;1>/*))#7yugzsnl

unsigned PSBT: cHNidP8BAPACAAAAAnAsovD3inipqw/6gR/wV1c8uFev5ChU5W1vEXFjc0jbAQAAAAD+////fAXSbRVyESONv+0F20DpqmCe2xeXIbILSVBKOzLk84YAAAAAAP7///8EAAsAAAAAAAAiACB5fbh2mFz9imjv68osMQDMF+cYfAYNjje2/j+ovzzC1dAHAAAAAAAAFgAU8Wr4xZtu4jTmFcNI1NrfA13Fk8W4CwAAAAAAACIAIB3VKAvXRu9Q5ae7iwhdc1tHOOJNTALAuITaHrKBZmXZNAgAAAAAAAAWABQSHep08D6wpgnwk6H13WXFMareZgdcAQAAAQErOBUAAAAAAAAiACBru4XV5bZ7veZogJA271+IXztCFmrAQHwg08urto+dvgEFR1IhAiizabo0ZVkJzvANrZz/jXkGXeNyqFU1lS99HNKFdUUXIQMs8p+QlBnWiDhb66TsB0AGxmx9kLBKDNVCF8Jy7Q1E51KuIgYCKLNpujRlWQnO8A2tnP+NeQZd43KoVTWVL30c0oV1RRcc5lAimTAAAIABAACAAAAAgAIAAIAAAAAAAQAAACIGAyzyn5CUGdaIOFvrpOwHQAbGbH2QsEoM1UIXwnLtDUTnHODFlcUwAACAAQAAgAAAAIACAACAAAAAAAEAAAAAAQEr8hIAAAAAAAAiACBru4XV5bZ7veZogJA271+IXztCFmrAQHwg08urto+dvgEFR1IhAiizabo0ZVkJzvANrZz/jXkGXeNyqFU1lS99HNKFdUUXIQMs8p+QlBnWiDhb66TsB0AGxmx9kLBKDNVCF8Jy7Q1E51KuIgYCKLNpujRlWQnO8A2tnP+NeQZd43KoVTWVL30c0oV1RRcc5lAimTAAAIABAACAAAAAgAIAAIAAAAAAAQAAACIGAyzyn5CUGdaIOFvrpOwHQAbGbH2QsEoM1UIXwnLtDUTnHODFlcUwAACAAQAAgAAAAIACAACAAAAAAAEAAAAAAQAiACB5fbh2mFz9imjv68osMQDMF+cYfAYNjje2/j+ovzzC1QEBR1IhAoPteEAS+GrvSCN/rKCG26jmSxdfL4ffjoqjc4x/0jivIQNWzRQre6KltOTcKdjtaRvPIsu9dwQ5T3cUsQ3TJAucBVKuIgICg+14QBL4au9II3+soIbbqOZLF18vh9+OiqNzjH/SOK8c5lAimTAAAIABAACAAAAAgAIAAIABAAAAAAAAACICA1bNFCt7oqW05Nwp2O1pG88iy713BDlPdxSxDdMkC5wFHODFlcUwAACAAQAAgAAAAIACAACAAQAAAAAAAAAAAAAA

The Issue, similar to above (+ missing witness_script)

Outputs array:

  "outputs": [
    {
      "redeem_script": {
        "asm": "0 797db876985cfd8a68efebca2c3100cc17e7187c060d8e37b6fe3fa8bf3cc2d5",
        "hex": "0020797db876985cfd8a68efebca2c3100cc17e7187c060d8e37b6fe3fa8bf3cc2d5",
        "type": "witness_v0_scripthash"
      },
      "witness_script": {
        "asm": "2 0283ed784012f86aef48237faca086dba8e64b175f2f87df8e8aa3738c7fd238af 0356cd142b7ba2a5b4e4dc29d8ed691bcf22cbbd7704394f7714b10dd3240b9c05 2 OP_CHECKMULTISIG",
        "hex": "52210283ed784012f86aef48237faca086dba8e64b175f2f87df8e8aa3738c7fd238af210356cd142b7ba2a5b4e4dc29d8ed691bcf22cbbd7704394f7714b10dd3240b9c0552ae",
        "type": "multisig"
      },
      "bip32_derivs": [
        {
          "pubkey": "0283ed784012f86aef48237faca086dba8e64b175f2f87df8e8aa3738c7fd238af",
          "master_fingerprint": "e6502299",
          "path": "m/48h/1h/0h/2h/1/0"
        },
        {
          "pubkey": "0356cd142b7ba2a5b4e4dc29d8ed691bcf22cbbd7704394f7714b10dd3240b9c05",
          "master_fingerprint": "e0c595c5",
          "path": "m/48h/1h/0h/2h/1/0"
        }
      ]
    },
    {
    },
    {
    },
    {
    }

Above, the change is the first output and we see "redeem_script", "witness_script" and "bip32_derivs" hints for both signers, but we don't see the same for the 3rd vout self-transfer which is empty.

After using bitcoin-core descriptorprocesspsbt we have updated information that signers like krux and seedsigner (perhaps others too?) are expecting for validating the 3rd output which belongs to the wallet.

corrected unsigned PSBT: cHNidP8BAPACAAAAAnAsovD3inipqw/6gR/wV1c8uFev5ChU5W1vEXFjc0jbAQAAAAD+////fAXSbRVyESONv+0F20DpqmCe2xeXIbILSVBKOzLk84YAAAAAAP7///8EAAsAAAAAAAAiACB5fbh2mFz9imjv68osMQDMF+cYfAYNjje2/j+ovzzC1dAHAAAAAAAAFgAU8Wr4xZtu4jTmFcNI1NrfA13Fk8W4CwAAAAAAACIAIB3VKAvXRu9Q5ae7iwhdc1tHOOJNTALAuITaHrKBZmXZNAgAAAAAAAAWABQSHep08D6wpgnwk6H13WXFMareZgdcAQAAAQErOBUAAAAAAAAiACBru4XV5bZ7veZogJA271+IXztCFmrAQHwg08urto+dvgEFR1IhAiizabo0ZVkJzvANrZz/jXkGXeNyqFU1lS99HNKFdUUXIQMs8p+QlBnWiDhb66TsB0AGxmx9kLBKDNVCF8Jy7Q1E51KuIgYCKLNpujRlWQnO8A2tnP+NeQZd43KoVTWVL30c0oV1RRcc5lAimTAAAIABAACAAAAAgAIAAIAAAAAAAQAAACIGAyzyn5CUGdaIOFvrpOwHQAbGbH2QsEoM1UIXwnLtDUTnHODFlcUwAACAAQAAgAAAAIACAACAAAAAAAEAAAAAAQEr8hIAAAAAAAAiACBru4XV5bZ7veZogJA271+IXztCFmrAQHwg08urto+dvgEFR1IhAiizabo0ZVkJzvANrZz/jXkGXeNyqFU1lS99HNKFdUUXIQMs8p+QlBnWiDhb66TsB0AGxmx9kLBKDNVCF8Jy7Q1E51KuIgYCKLNpujRlWQnO8A2tnP+NeQZd43KoVTWVL30c0oV1RRcc5lAimTAAAIABAACAAAAAgAIAAIAAAAAAAQAAACIGAyzyn5CUGdaIOFvrpOwHQAbGbH2QsEoM1UIXwnLtDUTnHODFlcUwAACAAQAAgAAAAIACAACAAAAAAAEAAAAAAQAiACB5fbh2mFz9imjv68osMQDMF+cYfAYNjje2/j+ovzzC1QEBR1IhAoPteEAS+GrvSCN/rKCG26jmSxdfL4ffjoqjc4x/0jivIQNWzRQre6KltOTcKdjtaRvPIsu9dwQ5T3cUsQ3TJAucBVKuIgICg+14QBL4au9II3+soIbbqOZLF18vh9+OiqNzjH/SOK8c5lAimTAAAIABAACAAAAAgAIAAIABAAAAAAAAACICA1bNFCt7oqW05Nwp2O1pG88iy713BDlPdxSxDdMkC5wFHODFlcUwAACAAQAAgAAAAIACAACAAQAAAAAAAAAAAAEBR1IhApGS6PO2OTiDBSrtTk+1ng0MYppE0KCIWt7MLXkPs97eIQOIdkSBMzsJ838eLMs4+dnHrEC9KS5QbtqhLIz8j59+iVKuIgICkZLo87Y5OIMFKu1OT7WeDQximkTQoIha3swteQ+z3t4c5lAimTAAAIABAACAAAAAgAIAAIAAAAAAAgAAACICA4h2RIEzOwnzfx4syzj52cesQL0pLlBu2qEsjPyPn36JHODFlcUwAACAAQAAgAAAAIACAACAAAAAAAIAAAAAAA==

  "outputs": [
    {
      "redeem_script": {
        "asm": "0 797db876985cfd8a68efebca2c3100cc17e7187c060d8e37b6fe3fa8bf3cc2d5",
        "hex": "0020797db876985cfd8a68efebca2c3100cc17e7187c060d8e37b6fe3fa8bf3cc2d5",
        "type": "witness_v0_scripthash"
      },
      "witness_script": {
        "asm": "2 0283ed784012f86aef48237faca086dba8e64b175f2f87df8e8aa3738c7fd238af 0356cd142b7ba2a5b4e4dc29d8ed691bcf22cbbd7704394f7714b10dd3240b9c05 2 OP_CHECKMULTISIG",
        "hex": "52210283ed784012f86aef48237faca086dba8e64b175f2f87df8e8aa3738c7fd238af210356cd142b7ba2a5b4e4dc29d8ed691bcf22cbbd7704394f7714b10dd3240b9c0552ae",
        "type": "multisig"
      },
      "bip32_derivs": [
        {
          "pubkey": "0283ed784012f86aef48237faca086dba8e64b175f2f87df8e8aa3738c7fd238af",
          "master_fingerprint": "e6502299",
          "path": "m/48h/1h/0h/2h/1/0"
        },
        {
          "pubkey": "0356cd142b7ba2a5b4e4dc29d8ed691bcf22cbbd7704394f7714b10dd3240b9c05",
          "master_fingerprint": "e0c595c5",
          "path": "m/48h/1h/0h/2h/1/0"
        }
      ]
    },
    {
    },
    {
      "witness_script": {
        "asm": "2 029192e8f3b6393883052aed4e4fb59e0d0c629a44d0a0885adecc2d790fb3dede 0388764481333b09f37f1e2ccb38f9d9c7ac40bd292e506edaa12c8cfc8f9f7e89 2 OP_CHECKMULTISIG",
        "hex": "5221029192e8f3b6393883052aed4e4fb59e0d0c629a44d0a0885adecc2d790fb3dede210388764481333b09f37f1e2ccb38f9d9c7ac40bd292e506edaa12c8cfc8f9f7e8952ae",
        "type": "multisig"
      },
      "bip32_derivs": [
        {
          "pubkey": "029192e8f3b6393883052aed4e4fb59e0d0c629a44d0a0885adecc2d790fb3dede",
          "master_fingerprint": "e6502299",
          "path": "m/48h/1h/0h/2h/0/2"
        },
        {
          "pubkey": "0388764481333b09f37f1e2ccb38f9d9c7ac40bd292e506edaa12c8cfc8f9f7e89",
          "master_fingerprint": "e0c595c5",
          "path": "m/48h/1h/0h/2h/0/2"
        }
      ]
    },
    {
    }

I'll note above that Bitcoin core didn't add the "redeem_script" field but did fill both the "witness_script" and "bip32_derivs" fields.

jdlcdl avatar Jul 02 '25 15:07 jdlcdl

Hi, thanks for opening the issue. At the moment, Keeper passes the data for change verification, but not for a self send, as we don't check if the destination address belongs to the same wallet (which is only used for consolidations). I think this can be a good feature to add though, so will add it to our backlog.

ben-kaufman avatar Jul 03 '25 07:07 ben-kaufman