BIP375: Add test vectors + validator #2046

pull macgyver13 wants to merge 10 commits into bitcoin:master from macgyver13:bip375-reference-testvectors-pr changing 24 files +4167 −1
  1. macgyver13 commented at 9:09 pm on November 26, 2025: contributor

    This PR provides bip-0375/bip375_test_vectors.json and a reference bip-0375/validator/validate_psbt.py for validating Sending Silent Payments with PSBTs. PSBTs are validated against v2 requirements with BIP-375 rules (building on BIP-352 silent payment derivation and BIP-374 DLEQ proofs).

    Changes since last force-push:

    • Add vendored dependencies in bip-0375/deps:
      • secp256k1lab (ECC operations)
      • bitcoin_test (PSBT parsing adapted from Bitcoin Core test framework)
    • Implement 4-stage sequential PSBT validation: structure, ECDH coverage + DLEQ correctness, input eligibility, and output script verification
    • Expanded test vector coverage:
      • mixed + ineligible inputs
      • output script validation with same scan key / spend key, same scan / different spend key, different scan key
      • introduce P2TR inputs
    • Add test vector version field (starting at 1.1)
    • Update BIP-0375 Test Vectors section

    Open Questions:

    • BIP-375 allows PSBT_OUT_SCRIPT field to be optional if PSBT_OUT_SP_V0_INFO field is present for an output, should PSBT_OUT_SCRIPT field with empty value_data be considered valid? - I prefer invalid
    • Should BIP text be clarified for Computing the Output Scripts as follows? - added ‘from eligible inputs

    Compute the PSBT_OUT_SCRIPT using the procedure in BIP352 but substituting a·Bscan with the PSBT_GLOBAL_SP_ECDH_SHARE for that scan key if available, or the sum of all PSBT_IN_SP_ECDH_SHAREs from eligible inputs for that scan key.

    Feedback welcome @andrewtoth @achow101 @theStack

    Description: BIP-375 Test Vectors Version: 1.1

    Invalid PSBTs: 23 psbt structure: missing PSBT_OUT_SP_V0_INFO field when PSBT_OUT_SP_V0_LABEL set psbt structure: incorrect byte length for PSBT_OUT_SP_V0_INFO field psbt structure: incorrect byte length for PSBT_IN_SP_ECDH_SHARE field psbt structure: incorrect byte length for PSBT_IN_SP_DLEQ field psbt structure: PSBT_GLOBAL_TX_MODIFIABLE field is non-zero when PSBT_OUT_SCRIPT set for sp output psbt structure: missing PSBT_OUT_SCRIPT field when sending to non-sp output psbt structure: empty PSBT_OUT_SCRIPT field when sending to non-sp output ecdh coverage: only one ineligible P2MS input when PSBT_OUT_SCRIPT set for sp output ecdh coverage: missing PSBT_IN_SP_ECDH_SHARE field for input 0 when PSBT_OUT_SCRIPT set for sp output ecdh coverage: missing PSBT_IN_SP_DLEQ field for input when PSBT_IN_SP_ECDH_SHARE set ecdh coverage: missing PSBT_GLOBAL_SP_DLEQ field when PSBT_GLOBAL_SP_ECDH_SHARE set ecdh coverage: invalid proof in PSBT_IN_SP_DLEQ field ecdh coverage: invalid proof in PSBT_GLOBAL_SP_DLEQ field ecdh coverage: missing PSBT_IN_BIP32_DERIVATION field for input when PSBT_IN_SP_DLEQ set ecdh coverage: output 1 missing ECDH share for scan key with one input / three sp outputs (different scan keys) ecdh coverage: input 1 missing ECDH share for output 1 with two inputs / two sp outputs (different scan keys) ecdh coverage: input 1 missing ECDH share for scan key with two inputs / one sp output input eligibility: segwit version greater than 1 in transaction inputs with sp output input eligibility: non-SIGHASH_ALL signature on input with sp output output scripts: P2TR input with NUMS internal key cannot derive sp output output scripts: PSBT_OUT_SCRIPT does not match derived sp output output scripts: two sp outputs (same scan / different spend keys) not sorted lexicographically by spend key output scripts: k values assigned to wrong output indices with three sp outputs (same scan / spend keys)

    Valid PSBTs: 18 can finalize: one input single-signer can finalize: two inputs single-signer using global ECDH share can finalize: two inputs single-signer using per-input ECDH shares can finalize: two inputs / two sp outputs with mixed global and per-input ECDH shares can finalize: one input / one sp output with both global and per-input ECDH shares can finalize: three sp outputs (different scan keys) with multiple global ECDH shares can finalize: one P2WPKH input / two mixed outputs - labeled sp output and BIP 32 change can finalize: one input / two sp outputs - output 0 has no label / output 1 uses label=0 convention for sp change can finalize: two sp outputs - output 0 uses label=3 / output 1 uses label=1 can finalize: two mixed input types - only eligible inputs contribute ECDH shares (P2SH excluded) can finalize: two mixed input types - only eligible inputs contribute ECDH shares (NUMS internal key excluded) can finalize: three sp outputs (same scan key) - each output has distinct k value can finalize: three sp outputs (same scan key) / two regular outputs - k values assigned independently of output index in progress: two P2TR inputs, neither is signed in progress: one P2TR input / one sp output with no ECDH shares when PSBT_OUT_SCRIPT field is not set in progress: two inputs / one sp output, input 1 missing ECDH share when PSBT_OUT_SCRIPT field is not set in progress: one input / two sp outputs, input 0 missing ECDH share for output 0 when PSBT_OUT_SCRIPT field is not set in progress: large PSBT with nine mixed inputs / six outputs - some inputs signed

    Summary: 41 passed, 0 failed

    Test vector generator is available in an external repo

  2. jonatack added the label Proposed BIP modification on Nov 27, 2025
  3. jonatack added the label Pending acceptance on Nov 27, 2025
  4. macgyver13 force-pushed on Dec 1, 2025
  5. macgyver13 force-pushed on Dec 3, 2025
  6. macgyver13 force-pushed on Dec 5, 2025
  7. macgyver13 force-pushed on Jan 8, 2026
  8. in bip-0375/test_runner.py:37 in 61d0c7bd80 outdated
    32+        # Decode PSBT
    33+        psbt_data = base64.b64decode(psbt_b64)
    34+
    35+        # Check magic bytes
    36+        if len(psbt_data) < 5 or psbt_data[:5] != b"psbt\xff":
    37+            return False, "Invalid PSBT magic"
    


    nymius commented at 7:29 pm on January 14, 2026:
    This check is also in parse_psbt_structure. I would keep it only in one of both places.
  9. in bip-0375/parser.py:61 in 61d0c7bd80 outdated
    56+            value_data = data[offset : offset + value_len]
    57+            offset += value_len
    58+
    59+            # Extract field type and handle key-value pairs
    60+            if key_data:
    61+                field_type = key_data[0]
    


    nymius commented at 7:38 pm on January 14, 2026:

    The extraction of field_type from key_data is odd. I would use de-structure assignment to keep them separated when assigning key_data, and also use the names stated in BIP 174, e.g.:

    0key_type, *key_data = data[offset : offset + key_len]
    
  10. in bip-0375/validator.py:136 in 45106322ef
    131+            witness_utxo = input_fields[PSBTFieldType.PSBT_IN_WITNESS_UTXO]
    132+            if check_invalid_segwit_version(witness_utxo):
    133+                return False, f"Input {i} uses segwit version > 1 with silent payments"
    134+
    135+    # Eligible input type requirement
    136+    # When silent payment outputs exist, ALL inputs must be eligible types
    


    nymius commented at 8:58 pm on January 14, 2026:
    What does ALL inputs must be eligible types mean in this context? This is checking all inputs are valid for shared secret derivation, which is not a condition all inputs must fulfill in order to create a silent payment transaction.

    macgyver13 commented at 0:11 am on January 16, 2026:
    Good catch - will address in the next revision
  11. in bip-0375/validator.py:194 in 45106322ef
    189+        if PSBTFieldType.PSBT_OUT_SP_V0_INFO not in output_fields:
    190+            continue
    191+
    192+        sp_info = output_fields[PSBTFieldType.PSBT_OUT_SP_V0_INFO]
    193+        if len(sp_info) != 66:
    194+            continue
    


    nymius commented at 1:43 pm on January 15, 2026:
    Shouldn’t this be a validation error?

    nymius commented at 1:47 pm on January 15, 2026:
    I see, you’re doing validation before. Ignore this comment.
  12. in bip-0375/test_vectors.json:144 in 45106322ef
    139+        }
    140+      ],
    141+      "comment": "Silent payment outputs require SIGHASH_ALL signatures only"
    142+    },
    143+    {
    144+      "description": "Mixed segwit versions with silent payments",
    


    nymius commented at 6:05 pm on January 15, 2026:
    I would prefer explicitness rather than conciseness in test case descriptions: Input with segwit script version greater than 1, even if it is more verbose.
  13. in bip-0375/test_vectors.json:145 in 45106322ef
    140+      ],
    141+      "comment": "Silent payment outputs require SIGHASH_ALL signatures only"
    142+    },
    143+    {
    144+      "description": "Mixed segwit versions with silent payments",
    145+      "psbt": "cHNidP8B+wQCAAAAAQIEAgAAAAEEBAEAAAABBQQBAAAAAQYBAwABDiCuv6p7LnQnsTi6F7UesBJ3TJOXBoHuPhb2Y3hjUklAJAEPBAAAAAABASughgEAAAAAACJSIIYiz2yIzTx5hSOFG+T1WYNgEYY+sDBYObtzXueh9KPpARAE/v///yIGA9NX98BxjyR44/2PjMwnKd3YwMyusfArGBpvRNQ7n42NBAAAAAABAwQBAAAAIh0C0Cn/lt4svPeCvkNZxIYg6pK83WvvAyuVFYuRoWk/tPghAlUWTnkm1Q1SoJ/5kGR6XpXB2xv8aKYW+8LaITkn+Yv/Ih4C0Cn/lt4svPeCvkNZxIYg6pK83WvvAyuVFYuRoWk/tPhAwdZ/OHiCv4F5FeoVgh1k1bODXB/AXFWM49gkkqF9kIwQSH27m93BCAyMLZwZcbJmCDxpBU4iGT8kQSisZnN+YAABAwgYcwEAAAAAAAEEIlEgIZ6/eW18O5peg4tLa+KXfHTrjWr+b09YgAaz1sNh63wBCUIC0Cn/lt4svPeCvkNZxIYg6pK83WvvAyuVFYuRoWk/tPgCTVGDU/S9GNdpz2j/Yu8QZptwhiRrCmQD/le95JIRRIsA",
    


    nymius commented at 6:08 pm on January 15, 2026:

    I wasn’t able to decode this psbt as it is using bitcoin-cli, have you?

    P.S.: I converted to hex and was able to decode, but it feels as something was off with bitcoin-cli.


    macgyver13 commented at 8:46 pm on January 15, 2026:

    First thank you for the review!
    Starting with this comment first, will be able to look at the rest over the next few days.

    I had not tested version 2 PSBTs against bitcoin core but there is a version limitation based on my quick scan of psbt.h

    • src/psbt.h:L79-80 defines PSBT_HIGHEST_VERSION = 0
    • src/psbt.h:L1315-1317
    0if (*m_version > PSBT_HIGHEST_VERSION) {
    1    throw std::ios_base::failure("Unsupported version number");
    2}
    

    nymius commented at 1:14 pm on January 16, 2026:
    Obviously, if core doesn’t support BIP 370, then why bitcoin-cli should decode it… well, why not? I overlooked this, thanks!
  14. in bip-0375/test_vectors.json:510 in 45106322ef
    505+          "is_silent_payment": true,
    506+          "sp_info": "02d029ff96de2cbcf782be4359c48620ea92bcdd6bef032b95158b91a1693fb4f8024d518353f4bd18d769cf68ff62ef10669b7086246b0a6403fe57bde49211448b",
    507+          "sp_label": null
    508+        }
    509+      ],
    510+      "comment": "Output script doesn't match BIP-352 computed address"
    


    nymius commented at 6:15 pm on January 15, 2026:
    What’s the difference between comment and description? Could we keep only one?

    macgyver13 commented at 0:15 am on January 16, 2026:
    I agree these test vectors don’t need both - will consolidate in next revision
  15. nymius commented at 6:27 pm on January 15, 2026: contributor

    cACK 45106322ef3b809e61a13d9b817eb38193fa19fa

    • I haven’t been able to decode the PSBT’s using bitcoin-cli decodepsbt in a per test basis. Did you have any issues?

    • I would consider copying the approach taken in bitcoin/bips#2084, and use secp256k1lab here.

    • As each PSBT change is reflected in BIP 174, maybe is worth moving the parsing, fields and PSBT validation logic to BIP 174 directory, and keep the role logic of each protocol on its own directory, like here.

  16. macgyver13 commented at 9:23 pm on January 15, 2026: contributor

    cACK 4510632

    • I haven’t been able to decode the PSBT’s using bitcoin-cli decodepsbt in a per test basis. Did you have any issues?

    Details in comment above - PSBT v2 not supported

    • I would consider copying the approach taken in #2084, and use secp256k1lab here.

    I agree that approach is better than the current bip-0374 import. The current import process would have to adapt to that change regardless. I’ll put that on the list for the next revision.

    • As each PSBT change is reflected in BIP 174, maybe is worth moving the parsing, fields and PSBT validation logic to BIP 174 directory, and keep the role logic of each protocol on its own directory, like here.

    Interesting idea. Are you suggesting a storage change for this PR or expand the scope of the PSBT parsing, fields and validation to v0 and other v2 fields and move to other BIPS directories?

  17. nymius commented at 1:17 pm on January 16, 2026: contributor

    Interesting idea. Are you suggesting a storage change for this PR or expand the scope of the PSBT parsing, fields and validation to v0 and other v2 fields and move to other BIPS directories?

    I’m suggesting the second one, but as it seems to involve more components, I wouldn’t pursue it in this PR.

  18. macgyver13 commented at 9:48 pm on January 22, 2026: contributor

    This PR depends on #2084.

    Converting to draft while dependent work is evaluated. In parallel reworking a few test cases for better coverage of spec. ie. (ECDH share coverage and unique identification)

  19. macgyver13 marked this as a draft on Jan 22, 2026
  20. murchandamus commented at 11:14 pm on February 27, 2026: member
    @macgyver13: It looks like your dependency moved forward. Could you take another look whether this is ready for an update?
  21. macgyver13 renamed this:
    BIP375: Add test vectors + runner
    BIP375: Add test vectors + validation runner
    on Mar 9, 2026
  22. macgyver13 renamed this:
    BIP375: Add test vectors + validation runner
    BIP375: Add test vectors + validator
    on Mar 9, 2026
  23. macgyver13 force-pushed on Mar 18, 2026
  24. BIP-375: Add bitcoin test framework as dependency - deps/bitcoin_test a8aa5ed548
  25. Squashed 'bip-0375/deps/secp256k1lab/' content from commit 44dc4bd
    git-subtree-dir: bip-0375/deps/secp256k1lab
    git-subtree-split: 44dc4bd893b8f03e621585e3bf255253e0e0fbfb
    eedb7f9a31
  26. Merge commit '96000a36c22f6528e834c54f0d115db675198e57' as 'bip-0375/deps/secp256k1lab' e70510193f
  27. BIP-375: add test vector file 5a0c74b568
  28. BIP-375: add BIP375PSBT extension classes
    BIP375PSBT (a PSBT subclass that deserializes into BIP375PSBTMap instances)
    BIP375PSBTMap (a PSBTMap subclass with BIP-375 field access helpers)
    f9594d3b28
  29. BIP-375: add test_runner and validate PSBT structure
    Implement psbt structure checks
    Add test_runner.py for processing test vectors
    c8babe2697
  30. BIP-375: add ecdh coverage validation
    Add deps/dleq.py (Adapted from bip-0374/reference.py)
    Extract pubkey from PSBT inputs 
    - PSBT_IN_BIP32_DERIVATION
    - PSBT_IN_WITNESS_UTXO for P2TR
    Add script type helpers
    - bip352 input eligibility helpers
    904659be70
  31. BIP-375: add input eligibility validation
    Verify segwit version >1 not used if silent payment outputs present (bip352)
    Verify SIGHASH_ALL requirement
    10459d1a49
  32. BIP-375: add output scripts validation
    Add support for computing bip352 output scripts
    Extract ECDH shares and public key from PSBT and aggregate both if necessary
    Refactor validate_ecdh_coverage to use collect_input_ecdh_and_pubkey
    e9f045c571
  33. BIP-375: update documentation
    Update Test Vectors section
    Add README.md to explain validation tooling and dependencies
    0cda30dc3d
  34. macgyver13 force-pushed on Mar 23, 2026
  35. macgyver13 marked this as ready for review on Mar 23, 2026
  36. macgyver13 commented at 10:43 pm on March 23, 2026: contributor

    Ready for review again — appreciate the patience. Main additions since marking as draft are in the PR description above.

    Will need feedback on the two open questions before this PR can be finalized.

  37. murchandamus commented at 1:14 am on March 25, 2026: member
    I see no review by the BIP owners so far. Are you talking to them out of band, or should the be requested here?
  38. andrewtoth commented at 1:17 am on March 25, 2026: contributor
    Sorry, haven’t had a chance to look at this yet. Will review shortly.
  39. macgyver13 commented at 1:48 am on March 25, 2026: contributor

    I see no review by the BIP owners so far. Are you talking to them out of band, or should the be requested here?

    theStack mentioned he would take a look soon when we spoke last week.

  40. andrewtoth commented at 9:46 pm on March 28, 2026: contributor

    This is awesome, thank you!

    BIP-375 allows PSBT_OUT_SCRIPT field to be optional if PSBT_OUT_SP_V0_INFO field is present for an output, should PSBT_OUT_SCRIPT field with empty value_data be considered valid? - I prefer invalid

    This seems out of scope for BIP375. I believe if present, the PSBT_OUT_SCRIPT should have a valid script. So, empty is invalid.

    Should BIP text be clarified for Computing the Output Scripts as follows? - added ‘from eligible inputs’

    Or perhaps the BIP can be modified to prohibit adding a share for ineligible inputs. I think that would fix this ambiguity and also catch issues sooner. Wdyt?

    I don’t see a test case for a P2PKH input, can we add one? Also, a test case of a global ECDH share (so signer has all keys) for a mix of eligible and ineligible inputs could be added.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-03-29 21:10 UTC

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