BIP375: Add test vectors + runner #2046

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

    This PR adds the test runner test_runner.py and test_vectors.json for demonstrating BIP 375 behavior. Care was taken to minimize dependencies required to evaluate the test vectors.

    Dependencies are referenced at runtime from bip-0374 instead of cloning locally.

    Test generation tools moved to external repo

    Feedback welcome @andrewtoth @achow101 @josibake

    Test runner output

     0Invalid test cases: 13
     1=== Running Invalid Test Cases ===
     2Test 1: Missing DLEQ proof for ECDH share
     3Test 2: Invalid DLEQ proof
     4Test 3: Non-SIGHASH_ALL signature with silent payments
     5Test 4: Mixed segwit versions with silent payments
     6Test 5: Silent payment outputs but no ECDH shares
     7Test 6: Global ECDH share without DLEQ proof
     8Test 7: Wrong SP_V0_INFO field size
     9Test 8: Mixed eligible and ineligible input types
    10Test 9: Wrong ECDH share size
    11Test 10: Wrong DLEQ proof size
    12Test 11: Label without SP_V0_INFO
    13Test 12: Address mismatch
    14Test 13: Both global and per-input ECDH shares
    15
    16=== Running Valid Test Cases ===
    17Test 14: Single signer with global ECDH share
    18Test 15: Multi-party with per-input ECDH shares
    19Test 16: P2WPKH to silent payment with change detection
    20Test 17: Silent payment to recipient with SP change (label=0)
    21Test 18: Multiple silent payment outputs to same scan key
    
  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. Add foundational PSBT parsing and basic validation
    - Add constants.py with BIP 375 PSBT field type definitions
    - Add parser.py with PSBT v2 structure parsing functions
    - Add minimal test_runner.py for basic structure validation
    - Validates PSBT magic bytes and parse-ability
    - All 17 test vectors pass basic structure checks
    - - Basic structure validation complete: 4 passed, 13 failed
    61d0c7bd80
  8. Add input validation for silent payment eligibility
    - Add inputs.py with input type validation helpers
    - Add dependencies from previous work
    - - deps/bip352_utils.py
    - - deps/secp256k1_374.py
    - Validate eligible input types (P2PKH, P2WPKH, P2TR, P2SH-P2WPKH)
    - Check segwit version restrictions (v0-v1 only)
    - Verify P2SH inputs are P2SH-P2WPKH
    - Update test_runner.py to validate inputs
    Input validation complete: 6 passed, 11 failed
    678a51270f
  9. Add DLEQ proof validation for ECDH shares
    - Add dleq.py with DLEQ proof validation functions
    - Extract public keys from BIP32 derivation fields
    - Validate global and per-input DLEQ proofs using BIP-374
    - Verify scan key consistency between ECDH and DLEQ fields
    - Prevent conflicting global/per-input ECDH for same scan key
    - Check ECDH shares exist for silent payment outputs
    - Update test_runner.py with comprehensive DLEQ validation
    DLEQ validation complete: 14 passed, 3 failed
    f35b2e8665
  10. Add complete BIP-375 PSBT validator
    - Add validator.py with comprehensive BIP-375 validation
    - Validate output field requirements (SCRIPT or SP_V0_INFO)
    - Check SP_V0_INFO field size (66 bytes)
    - Validate SP_V0_LABEL requires SP_V0_INFO
    - Enforce SIGHASH_ALL requirement for silent payments
    - Integrate all previous validation (inputs, DLEQ, ECDH)
    - Simplify test_runner.py to use validator module
    - Validation complete: 16 passed, 1 failed
    7b5ef465c8
  11. Add BIP-352 output script validation - address mismatch test case
    - Add validate_bip352_outputs() for output script verification
    - Support both global and per-input ECDH share modes
    - Update test_runner.py to pass test material to validator
    1d34a45473
  12. Add README
    - Details core files and dependencies
    - Link to test_generator.py for vector generation
    - Provide usage instructions for test_runner.py
    29f23e3d1c
  13. Add new test vector "Silent payment to recipient with SP change (label=0)"
    Fix compute output script ‘k’ bug - now increments for each output sharing the same scan key
    45106322ef
  14. macgyver13 force-pushed on Jan 8, 2026
  15. 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.
  16. 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]
    
  17. 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
  18. 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.
  19. 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.
  20. 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!
  21. 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
  22. 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.

  23. 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?

  24. 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.


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-01-22 09:10 UTC

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