Skip to content

fuzz: assert we accept any PSBT serialization we create#34725

Merged
achow101 merged 1 commit intobitcoin:masterfrom
darosior:2603_psbt_roundtrip
Mar 4, 2026
Merged

fuzz: assert we accept any PSBT serialization we create#34725
achow101 merged 1 commit intobitcoin:masterfrom
darosior:2603_psbt_roundtrip

Conversation

@darosior
Copy link
Member

@darosior darosior commented Mar 3, 2026

Invalid public keys were accepted in Musig2 partial signatures. Because we serialize invalid keys as the empty byte string, this would lead us to creating an invalid PSBT serializations.

This can be checked by reverting the first commit with the fix and simply running the target against the existing qa-assets corpus for the psbt harness.

This patch found the issue fixed in #34219 with a single run against the existing qa-assets corpus. It is useful to make sure there are no similar bugs, and we don't introduce roundtrip regressions outside of the specifc instance of accepting invalid public keys in Musig2 fields.

(Edited on March 4 to only contain the fuzz harness patch)

@DrahtBot
Copy link
Contributor

DrahtBot commented Mar 3, 2026

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK dergoegge, brunoerg, davidgumberg, achow101

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

No conflicts as of last run.

@achow101 achow101 added this to the 31.0 milestone Mar 3, 2026
@achow101
Copy link
Member

achow101 commented Mar 3, 2026

Can you share the fuzz test case that this fixes?

@darosior
Copy link
Member Author

darosior commented Mar 3, 2026

The input that triggers the crash is already present in qa-assets, and therefore should be run in CI. Here is the corresponding PSBT:

cHNidP8BADMzMzADAXQABPwBQUADAXQHAAAAHgAAACIAAAAAAAAAAAAaBwcHBwcFLQAAAAEBAAAA5AAAAQEfACJwAAD2AAAWABTUjtMRC9YAAAQE/wFIAAEEAwH8AUMcAgF0AE5TdDhpb3NfT2FzZY9idP8AJOwB/HQD4jAAAAAAgAABAAAAAAAAUgTiAgAAAAAAAEIzA0F0AAT8AUAoAEIdIPx0/FJSUlJSUlJSUlJSUlJSUlJSKysrK0gAAQQDAfwBQxwBCwAPgwFkAAAAAl2nYnT/AQBFQm1CbQEANiPf6vb//hcD+VVUKFVNQUFBQQnuc/8AGQAAHDIDQXQABPwBQCgAQh0g/HT8UlJSUlJSUlJSUlJSdAD8AQAABP8BSAABBAMB/AFDHAMBdEUBbAAcQAJ6h/j/BHoAYmoBAQEBAQsAD4MBZAAEAAKTlGJ0/wEARUJtQgIAABAAAABCNQNBdAAE/AFAKABCHSD8dPxSUlJSUvwE/AFAZAMBdAAMfAFBQHQAAAAQgAAAAAA=

Calling decodepsbt on it highlights the issue. Here is the output:

{
  "tx": {
    "txid": "566e1156d5f4152134d49dc08610e5b979e3de76fe5d5794d7de6f2cfc234661",
    "hash": "566e1156d5f4152134d49dc08610e5b979e3de76fe5d5794d7de6f2cfc234661",
    "version": 53490483,
    "size": 51,
    "vsize": 51,
    "weight": 204,
    "locktime": 14942208,
    "vin": [
      {
        "txid": "0707071a000000000000000000220000001e00000007740103404101fc040074",
        "vout": 755304199,
        "scriptSig": {
          "asm": "",
          "hex": ""
        },
        "sequence": 16842752
      }
    ],
    "vout": [
    ]
  },
  "global_xpubs": [
  ],
  "psbt_version": 0,
  "proprietary": [
  ],
  "unknown": {
  },
  "inputs": [
    {
      "witness_utxo": {
        "amount": 2704798.67781632,
        "scriptPubKey": {
          "asm": "0 d48ed3110bd600000404ff01480001040301fc01",
          "desc": "addr(bc1q6j8dxygt6cqqqpqyluq5sqqpqspsrlqp9t6tx9)#pdp4h8v0",
          "hex": "0014d48ed3110bd600000404ff01480001040301fc01",
          "address": "bc1q6j8dxygt6cqqqpqyluq5sqqpqspsrlqp9t6tx9",
          "type": "witness_v0_keyhash"
        }
      },
      "musig2_partial_sigs": [
        {
          "participant_pubkey": "03017445016c001c40027a87f8ff047a00626a01010101010b000f830164000400",
          "aggregate_pubkey": "0293946274ff010045426d420200001000000042350341740004fc01402800421d",
          "partial_sig": "fc74fc5252525252fc04fc014064030174000c7c014140740000001080000000"
        },
        {
          "participant_pubkey": "",
          "aggregate_pubkey": "03f9555428554d4141414109ee73ff001900001c320341740004fc01402800421d",
          "partial_sig": "fc74fc5252525252525252525252527400fc01000004ff01480001040301fc01"
        },
        {
          "participant_pubkey": "020174004e537438696f735f4f6173658f6274ff0024ec01fc7403e23000000000",
          "aggregate_pubkey": "",
          "partial_sig": "fc74fc52525252525252525252525252525252522b2b2b2b480001040301fc01"
        }
      ]
    }
  ],
  "outputs": [
  ],
  "fee": 2704798.67781632
}

@achow101
Copy link
Member

achow101 commented Mar 3, 2026

ACK fc2245e

@fanquake
Copy link
Member

fanquake commented Mar 4, 2026

Actually, is this a duplicate of #34219? Seems like that got review, but just stalled?

@darosior
Copy link
Member Author

darosior commented Mar 4, 2026

Oh i had missed it! I just pushed that as a separate PR while i was reviewing #21283.

The fix is virtually the same (as per #34725 (comment) i don't think IsFullyValid is necessary, but it's not important). However i think the fuzz harness patch here is important. The tests in #34219 are specific to this regression, but we should be testing that more generally we never produce a serialization we do not accept.

How about merging/backporting #34219 then i rebase this PR with only the fuzz harness commit, that does not necessarily need backporting?

@fanquake
Copy link
Member

fanquake commented Mar 4, 2026

How about merging/backporting #34219 then i rebase this PR with only the fuzz harness commit, that does not necessarily need backporting?

That seems fine.

@darosior darosior force-pushed the 2603_psbt_roundtrip branch from fc2245e to c383c3c Compare March 4, 2026 16:09
@darosior darosior changed the title Fix a PSBT serialization roundtrip issue fuzz: assert we accept any PSBT serialization we create Mar 4, 2026
@darosior
Copy link
Member Author

darosior commented Mar 4, 2026

Rebased after #34219 was merged, to only contain the patch to the fuzzing harness.

@davidgumberg
Copy link
Contributor

davidgumberg commented Mar 4, 2026

crACK c383c3c

Feel free to disregard as orthogonal or insignificant, but I think it would be valuable to also add a (programmatic) test for the particular case addressed in #34219 / in this PR prior to rebase either as a unit test (e.g. davidgumberg@a58ac09) or as a functional test case (e.g. davidgumberg@395ebfa). While redundant with the cases added in #34219 to ‎test/functional/data/rpc_psbt.json, I think tables of raw PSBT's are not trivial for a reader to review / comprehend.

@DrahtBot DrahtBot requested a review from achow101 March 4, 2026 16:51
@darosior darosior force-pushed the 2603_psbt_roundtrip branch from c383c3c to d76ec4d Compare March 4, 2026 16:55
This will prevent us from creating a serialization we do not accept
going forward.
Copy link
Member

@dergoegge dergoegge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK d76ec4d

@DrahtBot DrahtBot requested a review from davidgumberg March 4, 2026 16:58
@darosior
Copy link
Member Author

darosior commented Mar 4, 2026

@davidgumberg that feels really redundant, so i'm not too keen. Especially as it would still be specific to this very instance of the roundtrip bug, and not be able to catch others. The fuzz harness modification in this PR is also another test for the bug fixed in #34219, which i hope is easier for a reader to review / comprehend than the raw PSBT added there.

@DrahtBot DrahtBot removed the CI failed label Mar 4, 2026
Copy link
Contributor

@brunoerg brunoerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code review ACK d76ec4d

@davidgumberg
Copy link
Contributor

davidgumberg commented Mar 4, 2026

crACK d76ec4d

Ran fuzzing for ~20 minutes with no issues.

Especially as it would still be specific to this very instance of the roundtrip bug, and not be able to catch others.

That's what I intended, but I'm satisfied that checking roundtripping is very likely to catch any issue related to deserializing a key that fails CPubKey::IsValid() since 'IsValidity' and 'Serializeability' happen to be the same for pubkeys. Coverage will still be missing (I think) for pubkeys that are not points but have valid length prefixes, but I'm inclined to agree with your comment above that IsFullyValid() is overkill, so probably fine to remain untested.

@achow101
Copy link
Member

achow101 commented Mar 4, 2026

ACK d76ec4d

@achow101 achow101 merged commit 083242a into bitcoin:master Mar 4, 2026
26 checks passed
@darosior darosior deleted the 2603_psbt_roundtrip branch March 4, 2026 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants