BIP-376: add python ref implementation and initial test vectors #2139

pull lucia-w wants to merge 5 commits into bitcoin:master from lucia-w:bip-0376 changing 19 files +1828 −2
  1. lucia-w commented at 3:59 AM on April 12, 2026: none
    • This PR adds a reference implementation and test vectors for Silent Payment input signing behavior.
  2. murchandamus added the label Proposed BIP modification on Apr 12, 2026
  3. murchandamus added the label Pending acceptance on Apr 12, 2026
  4. murchandamus commented at 5:49 PM on April 12, 2026: member

    Thanks for your submission. cc'ing the author @nymius for review.

  5. in bip-0376/reference.py:2 in 8c38c9e2a0 outdated
       0 | @@ -0,0 +1,223 @@
       1 | +#!/usr/bin/env python3
       2 | +"""BIP-0376 reference implementation and test vector runner.
    


    nymius commented at 12:51 PM on April 14, 2026:

    I recommend you to follow the approach taken in #2087 and #2046 , use secp256k1lab and the components from bitcoin_test that you need. That would focus the review process on BIP 376.


    lucia-w commented at 9:41 AM on April 27, 2026:

    Makes sense, thank you

  6. in bip-0376/test-vectors.json:62 in 8c38c9e2a0 outdated
      57 | +      "given": {
      58 | +        "spend_seckey": "0000000000000000000000000000000000000000000000000000000000000000",
      59 | +        "tweak": "ac7b0d0420f0d4a567d9abcb8a52e02cfae21690fd8d2d5934370dcc5aaee221",
      60 | +        "output_pubkey": "528b75296fa646acecf3fcb7c7697f92f7645ea0e41e6ee8a66554739d2da028"
      61 | +      },
      62 | +      "error_substr": "spend key out of range"
    


    nymius commented at 12:54 PM on April 14, 2026:

    These are unnecessary and constraint the implementation, I would remove them.


    lucia-w commented at 9:43 AM on April 27, 2026:

    Done, could you please review again

  7. nymius commented at 1:07 PM on April 14, 2026: contributor

    Approach NACK 8c38c9e2a0db57a243237c05f06da3342ec8a95f

    Thanks for working on this. Although your changes are exercising the behavior of the signer role, my expectations for the test cases are inclined to what we already have in BIP 174 or is currently being worked on for BIP 375 (#2046) There we have full serialized PSBT tests. As this BIP is focused towards PSBTs, I think that's the way to proceed.

  8. jonatack added the label PR Author action required on Apr 14, 2026
  9. lucia-w force-pushed on Apr 26, 2026
  10. murchandamus removed the label PR Author action required on Apr 27, 2026
  11. murchandamus requested review from nymius on Apr 27, 2026
  12. in bip-0376/reference.py:12 in 722f501a02
       7 | +
       8 | +import json
       9 | +import sys
      10 | +from pathlib import Path
      11 | +
      12 | +BIP375_DIR = Path(__file__).resolve().parents[1] / "bip-0375"
    


    nymius commented at 12:23 PM on April 29, 2026:

    This is brittle, I would do exactly what bip-0375 does and copy the whole secp256k1lab source code in this directory, and then do the Path magic.

  13. in bip-0376/psbt_bip376.py:60 in 722f501a02
      55 | +        self.version = 0
      56 | +        if PSBT_GLOBAL_VERSION in self.g.map:
      57 | +            assert PSBT_GLOBAL_INPUT_COUNT in self.g.map
      58 | +            assert PSBT_GLOBAL_OUTPUT_COUNT in self.g.map
      59 | +            self.version = struct.unpack("<I", self.g.map[PSBT_GLOBAL_VERSION])[0]
      60 | +            assert self.version in [0, 2]
    


    nymius commented at 2:10 PM on April 29, 2026:

    BIP 376 is backwards compatible with PSBTv2. It isn't compatible with PSBTv0, as the new fields are marked as excluded.


    lucia-w commented at 10:04 AM on May 7, 2026:

    thank you

  14. nymius commented at 3:54 PM on April 29, 2026: contributor

    Thanks for the update. Let me explain this better:

    I would create a dependencies or deps dir with the secp256k1lab@1.0.0 source code and the code from bitcoin core test framework like BIP 375 does: https://github.com/bitcoin/bips/tree/master/bip-0375

    And I recommend you to do it with git subtree add --prefix=bip-0352/secp256k1lab --squash https://github.com/secp256k1lab/secp256k1lab v1.0.0 command, like in: #2087, it is redundant, but is self contained.

    For the test implementation, I don't think the spend seckey checks belong here, because they are in the domain of BIP 340.

    The test cases I have in mind for now are:

    • Updater adds PSBT_IN_SP_TWEAK.
    • Updater adds PSBT_IN_SP_TWEAK and PSBT_IN_SP_SPEND_BIP32_DERIVATION.
    • Signer sets the PSBT_IN_TAP_KEY_SIG with expected signature for input with PSBT_IN_SP_TWEAK set using PSBT_IN_SP_SPEND_BIP32_DERIVATION.
    • Signer sets the PSBT_IN_TAP_KEY_SIG with expected signature for input with PSBT_IN_SP_TWEAK without PSBT_IN_SP_SPEND_BIP32_DERIVATION field.
    • Signer sets the PSBT_IN_TAP_KEY_SIG with expected signature with d.G odd, for input with PSBT_IN_SP_TWEAK set.
    • Signer fails if the x-coordinate of d.G does not equal the output key in the P2TR output script.
    • Input finalizer fails to verify PSBT_IN_TAP_KEY_SIG for PSBT_IN_SP_TWEAK (i.e., wrong signature).
    • Input finalizer removes PSBT_IN_SP_TWEAK, PSBT_IN_SP_SPEND_BIP32_DERIVATION, PSBT_IN_TAP_KEY_SIG, and PSBT_IN_WITNESS_UTXO fields for an input where PSBT_IN_SP_TWEAK is set, and the PSBT_IN_FINAL_SCRIPTWITNESS is present.

    I have been thinking in a way to standarize the PSBT test vectors, following BIP 375 approach, and this is the structure I came up with:

    {
      "description": "string", // BIP 376 test vectors
      "version": "string", // "0.1.0"
      "notes": [],
      "cases": [
        {
          "description": "string",
          "psbt": {
            "hex": "string",
            "base64": "string" // This one should also be optional, I think it only makes sense for BIP 174
          },
          "supplementary": { // Supplementary can hold multiple optional fields, which depend of the case you are testing, I've added the ones already required for signing
            "spend_seckey": "string",
            "message": "string",
            "aux_rand": "string" // I'm not sure about this one, we can do like BIP 340 reference and derive one each time using incremental numbers
            "task": "string", // This is required, but to keep compatibility with BIP 375 test vectors I placed it here. It can be one of [fail, fail_sign, update, finalize]
          }
        }
      ]
    }
    
  15. jonatack renamed this:
    BIP-376: Silent Payment input signing behavior
    BIP-376: add python ref implementation and initial test vectors
    on May 5, 2026
  16. jonatack added the label PR Author action required on May 5, 2026
  17. jonatack commented at 8:13 PM on May 5, 2026: member

    Hi @lucia-w, labeled this as waiting for your update following review feedback by the BIP author. I'll review as well after that next cycle.

  18. jonatack removed the label PR Author action required on May 8, 2026
  19. This fills in the remaining TODO sections in BIP-376 652b940f9e
  20. BIP-0376: use PSBT vectors for signer tests b0b2cf47a9
  21. bip-0376: remove error message checks from invalid vectors 9ebb27f651
  22. BIP-0376: use PSBT vectors for signer tests 58a43d40f2
  23. bip-0376: vendor test deps and add PSBTv2 vectors b718f2e610
  24. lucia-w force-pushed on May 9, 2026
  25. in bip-0376/test-vectors.json:11 in b718f2e610
       6 | +    "The supplementary.task field selects the role operation: update, sign, fail_sign, finalize, or fail.",
       7 | +    "Supplementary fields provide deterministic signing material for vector validation only."
       8 | +  ],
       9 | +  "cases": [
      10 | +    {
      11 | +      "description": "Updater adds PSBT_IN_SP_TWEAK",
    


    nymius commented at 12:59 PM on May 11, 2026:

    I would prefix each test case with the "Valid: "/ Invalid: " prefix as it fits.

  26. in bip-0376.mediawiki:157 in b718f2e610
     153 | +It demonstrates the Signer behavior specified in this BIP:
     154 | +
     155 | +* Key derivation using ''d = (b<sub>spend</sub> + tweak) mod n''.
     156 | +* Key negation when ''d·G'' has odd y-coordinate.
     157 | +* Verification that the resulting x-only public key matches the output key ''P''.
     158 | +* BIP 340 signing with the derived key.
    


    nymius commented at 12:59 PM on May 11, 2026:

    This should be updated.

  27. in bip-0376.mediawiki:167 in b718f2e610
     164 | +
     165 | +The vector set includes:
     166 | +
     167 | +* Valid signing cases with and without key negation.
     168 | +* Invalid cases for output-key mismatch, zero tweaked key, and out-of-range spend key.
     169 | +
    


    nymius commented at 1:00 PM on May 11, 2026:

    This should be updated too. I would use the test cases descriptions here, flagging each test case as valid or invalid.

  28. in bip-0376/reference.py:1 in b718f2e610


    nymius commented at 1:12 PM on May 11, 2026:

    This file has read/write/execute permissions (0775) I would keep it as read/write only (0664) and execute it through python, to match other references implementation.


    nymius commented at 1:39 PM on May 11, 2026:

    Could you share the way you're generating this file? I would ease the review.

  29. in bip-0376/test-vectors.json:129 in b718f2e610
     124 | +        "message": "289e5175e02c788c2d442cfe81d6be0533d8c13e253ef763fda45d37accfe4d4"
     125 | +      }
     126 | +    },
     127 | +    {
     128 | +      "description": "Input finalizer removes PSBT_IN_SP_TWEAK, PSBT_IN_SP_SPEND_BIP32_DERIVATION, PSBT_IN_TAP_KEY_SIG, and PSBT_IN_WITNESS_UTXO fields for a finalized input",
     129 | +      "psbt": {
    


    nymius commented at 1:35 PM on May 11, 2026:

    I would move this to supplementary, "psbts" field, and rename this psbt field to "expected".

    For reference, I'm applying the same patterns for a bip174 test vector runner here git.rust-bitcoin.org/nymius/rust-psbt. The runner is the tests/bip174.rs file, and the test vectors are in tests/data/bip174.json.

  30. in bip-0376/test-vectors.json:37 in b718f2e610
      32 | +      },
      33 | +      "supplementary": {
      34 | +        "task": "update",
      35 | +        "tweak": "ac7b0d0420f0d4a567d9abcb8a52e02cfae21690fd8d2d5934370dcc5aaee221",
      36 | +        "spend_pubkey": "02812c369c23c4185755813b40f4edf0cedffbc2496f7802932513ead763ffaef8",
      37 | +        "spend_bip32_derivation": "00000000"
    


    nymius commented at 1:39 PM on May 11, 2026:

    We should add test cases with more inputs that are not BIP 376 compatible. For that, we need to be able to differentiate the inputs to which we have to apply the updates., I would use an input based array of objects to provide the data in that case.

  31. nymius commented at 1:40 PM on May 11, 2026: contributor

    Please, keep the commit message generated by the git subtree command, is easier to audit the code if the commit of the original version is in the message. The PR history after executing the command should look like this commit and this commit.

    Also, to allow the same auditability for the bitcoin deps, include the hash of the commit from bitcoin core from which you adapted the messages.py and psbt.py files.


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-05-19 06:50 UTC