BIP-376: Silent Payment input signing behavior#2139
BIP-376: Silent Payment input signing behavior#2139lucia-w wants to merge 6 commits intobitcoin:masterfrom
Conversation
lucia-w
commented
Apr 12, 2026
- This PR adds a reference implementation and test vectors for Silent Payment input signing behavior.
|
Thanks for your submission. cc'ing the author @nymius for review. |
nymius
left a comment
There was a problem hiding this comment.
Approach NACK 8c38c9e
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.
| @@ -0,0 +1,223 @@ | |||
| #!/usr/bin/env python3 | |||
| """BIP-0376 reference implementation and test vector runner. | |||
| "tweak": "ac7b0d0420f0d4a567d9abcb8a52e02cfae21690fd8d2d5934370dcc5aaee221", | ||
| "output_pubkey": "528b75296fa646acecf3fcb7c7697f92f7645ea0e41e6ee8a66554739d2da028" | ||
| }, | ||
| "error_substr": "spend key out of range" |
There was a problem hiding this comment.
These are unnecessary and constraint the implementation, I would remove them.
There was a problem hiding this comment.
Done, could you please review again
There was a problem hiding this comment.
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_TWEAKandPSBT_IN_SP_SPEND_BIP32_DERIVATION. - Signer sets the
PSBT_IN_TAP_KEY_SIGwith expected signature for input withPSBT_IN_SP_TWEAKset usingPSBT_IN_SP_SPEND_BIP32_DERIVATION. - Signer sets the
PSBT_IN_TAP_KEY_SIGwith expected signature for input withPSBT_IN_SP_TWEAKwithoutPSBT_IN_SP_SPEND_BIP32_DERIVATIONfield. - Signer sets the
PSBT_IN_TAP_KEY_SIGwith expected signature withd.Godd, for input withPSBT_IN_SP_TWEAKset. - Signer fails if the x-coordinate of
d.Gdoes not equal the output key in the P2TR output script. - Input finalizer fails to verify
PSBT_IN_TAP_KEY_SIGforPSBT_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, andPSBT_IN_WITNESS_UTXOfields for an input wherePSBT_IN_SP_TWEAKis set, and thePSBT_IN_FINAL_SCRIPTWITNESSis 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]
}
}
]
}| import sys | ||
| from pathlib import Path | ||
|
|
||
| BIP375_DIR = Path(__file__).resolve().parents[1] / "bip-0375" |
There was a problem hiding this comment.
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.
| assert PSBT_GLOBAL_INPUT_COUNT in self.g.map | ||
| assert PSBT_GLOBAL_OUTPUT_COUNT in self.g.map | ||
| self.version = struct.unpack("<I", self.g.map[PSBT_GLOBAL_VERSION])[0] | ||
| assert self.version in [0, 2] |
There was a problem hiding this comment.
BIP 376 is backwards compatible with PSBTv2. It isn't compatible with PSBTv0, as the new fields are marked as excluded.