Skip to content

BIP376: Spending Silent Payment outputs with PSBTs#2089

Open
nymius wants to merge 1 commit intobitcoin:masterfrom
nymius:bip-spending-silent-payments-outputs-with-psbts
Open

BIP376: Spending Silent Payment outputs with PSBTs#2089
nymius wants to merge 1 commit intobitcoin:masterfrom
nymius:bip-spending-silent-payments-outputs-with-psbts

Conversation

@nymius
Copy link
Contributor

@nymius nymius commented Jan 19, 2026

Abstract

This document proposes an additional per input field for BIP 370 PSBTv2 that allows BIP 352 silent payment tweaks to be included in a PSBT of version 2. This field will be relevant to silent payment outputs spending.

Mailing list discussion: https://groups.google.com/g/bitcoindev/c/Kap7NMwzl2k
Delving bitcoin discussion: https://delvingbitcoin.org/t/bip352-psbt-support/877/32

Copy link
Member

@murchandamus murchandamus left a comment

Choose a reason for hiding this comment

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

This is a good start, most parts seem to already be here. Would be great to get some more eyes on this from other people working on Silent Payments.

@nymius
Copy link
Contributor Author

nymius commented Jan 29, 2026

I have pushed the changes in separated commits, to squash later.
Thanks for the feedback!

@murchandamus
Copy link
Member

What’s the next step here? Will you be asking for people to provide some review, do you still have planned work, are there any open questions?

@nymius
Copy link
Contributor Author

nymius commented Feb 4, 2026

So far, I haven't received any negative feedback on the proposal, so I plan to do a second round of review on the rationale. I would like to steel-man the argument for this approach against the other alternatives.
Since the feedback occurred outside the designated channels, I will try to move the discussion there whenever possible.

@murchandamus
Copy link
Member

Assigned BIP376. Please update the BIP and Assigned headers in the preamble, add a table entry in the README for your proposal, and update your documents filename.

@murchandamus murchandamus changed the title BIP Draft: Spending Silent Payment outputs with PSBTs BIP376: Spending Silent Payment outputs with PSBTs Feb 5, 2026
@nymius nymius force-pushed the bip-spending-silent-payments-outputs-with-psbts branch from 43d3ce2 to aa4c4ed Compare February 5, 2026 20:18
@nymius
Copy link
Contributor Author

nymius commented Feb 5, 2026

While weighing the requirement of BIP 375, I detected there is no mention of how to source the base key to which the PSBT_IN_SP_TWEAK is added.

I have multiple ideas for this:

  • The 33 byte spend public key is included in the keydata from the new field.
  • The derivation information of the spend key is included in the corresponding BIP 32 fields.
  • The spend public key is transformed into a 32 xonly public key and it is included in one of the BIP 371 fields and both parities are considered.
  • This is left unspecified and the signer should implement a way to match the private key with the input and the tweak.

This would be a source of ambiguity. I will consider the options and update once I've a conclusion.

@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Feb 6, 2026
@murchandamus
Copy link
Member

Okay, I’ll consider this in your court until you state otherwise in a comment here. :)

@craigraw
Copy link
Contributor

craigraw commented Feb 6, 2026

Good catch. I don't think this should be left unspecified.

Further, I think this choice can be simplified by considering the requirements of hardware wallets. I checked the firmware for both the Coldcard and the BitBox02 - both derive private keys from derivation paths, not public keys.

While you could use PSBT_IN_BIP32_DERIVATION, there may be some confusion with PSBT_OUT_TAP_BIP32_DERIVATION since BIP352 spends Taproot outputs.

To avoid this I suggest creating a new field called PSBT_IN_SP_SPEND_BIP32_DERIVATION which contains the same keydata and valuedata definitions used for PSBT_IN_BIP32_DERIVATION.

@nymius nymius force-pushed the bip-spending-silent-payments-outputs-with-psbts branch from 09e9b51 to 2a3ca6a Compare February 11, 2026 16:34
@nymius
Copy link
Contributor Author

nymius commented Feb 11, 2026

I have revised the spec to address grammar and phrasing, and included the following updates regarding content:

  • Following @craigraw suggestion (thanks!) I added a new PSBT_IN_SP_BIP32_DERIVATION field:
    • I considered other alternatives that do not adhere to the BIP 32 scheme, such as FROST. However, as the PSBT specification is primarily built around the BIP 32 derivation scheme, I decided not to deviate from that standard. When the time comes, these protocols will likely propose updates to align with the PSBT specification. I added a reference at the end explaining this.
    • I moved the PSBT_IN_SP_TWEAK below this new field.
    • I added a paragraph to the rationale justifying the creation of this new field rather than reusing one of the existing *_BIP32_DERIVATION fields.
  • I removed a paragraph from the rationale regarding the complexity of making BIP 341 and BIP 352 compatible to reuse Taproot BIP 371 fields (03e925c): I realized that the discussion of whether BIP 352 could have been designed to comprise BIP 341 tag hashes pertains to BIP 352 itself, not this document. This BIP should address BIP 352 as currently defined; changes to the BIP 352 standard belong to a different proposal.

Copy link
Contributor

@macgyver13 macgyver13 left a comment

Choose a reason for hiding this comment

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

Concept ACK 2a3ca6a

Thank you for putting this BIP forward. I support the addition of these two PSBT fields for spending Silent Payments outputs.

Regarding the BIP text I would like to see more explicit use of language to describe the inclusion of these fields for spending Silent Payments, similar to BIP-375 (PSBT_OUT_SCRIPT / PSBT_OUT_SP_V0_INFO). I think the Rationale explains the reasoning but having a more clear specification would reduce ambiguity. I am on the fence as to whether to include the following as general spec statements or in a specific role.

  • PSBT_IN_SP_TWEAK must be included when an input spends a Silent Payment output
  • PSBT_IN_SP_SPEND_BIP32_DERIVATION should be included when spending a Silent Payment output using BIP 32 derivation schemes

* ''hash<sub>tag</sub>(x)'': refers to ''SHA256(SHA256(tag) || SHA256(tag) || x)''.

=== Fields ===

Copy link
Contributor

Choose a reason for hiding this comment

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

I would suggest including the following:

This document specifies new fields and new field inclusion/exclusion requirements.

The new per-input types are defined as follows:

@nymius
Copy link
Contributor Author

nymius commented Feb 17, 2026

  • PSBT_IN_SP_TWEAK must be included when an input spends a Silent Payment output

  • PSBT_IN_SP_SPEND_BIP32_DERIVATION should be included when spending a Silent Payment output using BIP 32 derivation schemes

I agree, I will add them to the Updater in the same fashion as BIP 375.

What is the reason for PSBT_IN_SP_SPEND_BIP32_DERIVATION to be a should and not a must?

@macgyver13
Copy link
Contributor

What is the reason for PSBT_IN_SP_SPEND_BIP32_DERIVATION to be a should and not a must?

I agree must is fine here too. I was erroring on conservative specification constraint.

@nymius nymius force-pushed the bip-spending-silent-payments-outputs-with-psbts branch from fbc81c7 to f6ef1a8 Compare March 5, 2026 19:15
@nymius
Copy link
Contributor Author

nymius commented Mar 5, 2026

I've included a preamble to the Field specification, and expanded on the requirements of the Updater role.

I've squashed all commits in f6ef1a8.

I'm open to receive another round of reviews.

cc: @macgyver13 @craigraw

@nymius nymius force-pushed the bip-spending-silent-payments-outputs-with-psbts branch from f6ef1a8 to 75b7922 Compare March 5, 2026 19:21
@nymius
Copy link
Contributor Author

nymius commented Mar 5, 2026

Included a grammar change that was left outside of last push.

Copy link
Contributor

@craigraw craigraw left a comment

Choose a reason for hiding this comment

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

Added comments inline. My major comment is around the lack of Signer and Finalizer roles. The Signer must verify the tweak provided by the Updater for safety.


=== Motivation ===

BIP 352 specify the Silent Payment protocol, which provides a new way to create P2TR outputs and spend them.
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: use specifies instead of specify.

| Silent Payment Spend Key BIP 32 Derivation Path<ref name="why_sticking_to_bip32_derivation">''' Why only considering BIP 32 for spend key generation?''' Although alternative key derivation methods exist (e.g., FROST) and have devised mechanisms to interact with PSBTs without modifying the format, the vast majority of hardware wallets are architected around BIP 32 derivation scheme. As primary consumers of the PSBT format, these devices have significantly influenced its design. Consequently, this BIP avoids preemptively enforcing a shift away from the established BIP 32 paradigm.</ref>
| <tt>PSBT_IN_SP_SPEND_BIP32_DERIVATION = 0x1f</tt>
| <tt><33-byte spend key></tt>
| The 33-byte spend public key locking this input.
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be more accurate to say The 33-byte spend public key used to derive the key locking this input. The tweaked key actually locks the input.

| <tt>PSBT_IN_SP_TWEAK = 0x20</tt>
| None
| No key data
| <tt><32-byte hash></tt>
Copy link
Contributor

Choose a reason for hiding this comment

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

<32-byte hash> is misleading. When a label is used, the value is t_k + label_tweak — a sum of two scalars, not a hash. Should be <32-byte tweak> to match the field name and the description.

| 2
|}

Per [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#spending BIP 352 spending] the <tt><32-byte-hash></tt> is ''hash<sub>BIP0352/SharedSecret</sub>(ser<sub>P</sub>(ecdh_shared_secret) || ser<sub>32</sub>(k))''
Copy link
Contributor

Choose a reason for hiding this comment

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

Same issue: <32-byte-hash> should be <32-byte tweak> for consistency.


Per [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#spending BIP 352 spending] the <tt><32-byte-hash></tt> is ''hash<sub>BIP0352/SharedSecret</sub>(ser<sub>P</sub>(ecdh_shared_secret) || ser<sub>32</sub>(k))''

or ''hash<sub>BIP0352/SharedSecret</sub>(ser<sub>P</sub>(ecdh_shared_secret) || ser<sub>32</sub>(k)) + hash<sub>BIP0352/Label</sub>(ser<sub>256</sub>(b<sub>scan</sub>) || ser<sub>32</sub>(m)'',
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing a closing parenthesis here.


The updater '''must add''' <tt>PSBT_IN_SP_TWEAK</tt> when an input spends a Silent Payment output.

The updater '''must add''' <tt>PSBT_IN_SP_SPEND_BIP32_DERIVATION_TWEAK</tt> when spending a Silent Payment output using BIP 32 derivation scheme. If the updater does not want to reveal the fingerprint or derivation path, it can set the value of the field to zero.
Copy link
Contributor

Choose a reason for hiding this comment

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

Field name typo: PSBT_IN_SP_SPEND_BIP32_DERIVATION_TWEAK should be PSBT_IN_SP_SPEND_BIP32_DERIVATION.

Also, "set the value of the field to zero" is a little ambiguous. Should clarify the structure, for example: "it can set the value to a 4-byte zero fingerprint with an empty derivation path".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree, I took this formula from BIP 375, so this should be amended there too.

I will use: it can set the value to a 4-byte zero fingerprint with no derivation paths


Assuming different tweaking schemes available, <tt>PSBT_IN_TAP_RAW_TWEAK</tt> would be a more general solution, but PSBT fields are usually specified as to the nature of the contents, and is unclear how a hardware wallet will determine what the content of the field were in the first more general case.

The inclusion of the tweak in the PSBT is insufficient in isolation; it must be accompanied by the information required to derive the correct private key. Silent Payment spend public key cannot utilize <tt>PSBT_IN_TAP_BIP32_DERIVATION</tt> because BIP 352 specifies 33-byte spend keys, which do not fit within this <tt>keydata</tt> field. Furthermore, reliance on <tt>PSBT_IN_BIP32_DERIVATION</tt> is precluded because BIP 352 spending rules follow BIP 341, which mandates the use of Schnorr signatures.
Copy link
Contributor

Choose a reason for hiding this comment

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

The rationale explains that PSBT_IN_TAP_BIP32_DERIVATION can't be used because BIP 352 uses 33-byte spend keys, but doesn't explain why 33-byte (compressed) form is needed rather than 32-byte x-only. The reason is that the spend key is an intermediate value, and the parity matters when computing d = b_spend + tweak and then checking against the x-only output key.

Copy link
Contributor Author

@nymius nymius Mar 6, 2026

Choose a reason for hiding this comment

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

This left me wondering why spend/scan key were left uncompressed not made x-only and force script pub key parity in the silent payment derivation. Fingerprinting? (again, I confused key parity with x-only keys)

It would be a good addition to BIP 352 rationales.

The updater '''must add''' <tt>PSBT_IN_SP_TWEAK</tt> when an input spends a Silent Payment output.

The updater '''must add''' <tt>PSBT_IN_SP_SPEND_BIP32_DERIVATION_TWEAK</tt> when spending a Silent Payment output using BIP 32 derivation scheme. If the updater does not want to reveal the fingerprint or derivation path, it can set the value of the field to zero.

Copy link
Contributor

Choose a reason for hiding this comment

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

Roles for the Signer and Finalizer are not present. I think they need to be, particularly for verifying the tweak is correct. Without it, a signer blindly trusts the updater's tweak. By checking d*G == P (where P is determined from the required PSBT_IN_WITNESS_UTXO field), the signer confirms the tweak is consistent with the output being spent. This is cheap (one EC multiplication) and prevents signing for an attacker-controlled key.

The Finalizer role should specify the additional cleanup required.

I suggest the following:

==== Signer ====

For each input that has a <tt>PSBT_IN_SP_TWEAK</tt> field set, the Signer must determine the spend private key <tt>b<sub>spend</sub></tt> using the derivation path provided in <tt>PSBT_IN_SP_SPEND_BIP32_DERIVATION</tt>. If this field is not present, or the Signer does not have the key matching the indicated fingerprint and path, the Signer must skip this input.

The Signer must compute the signing private key <tt>d = (b<sub>spend</sub> + tweak) mod n</tt>, where <tt>tweak</tt> is the value of <tt>PSBT_IN_SP_TWEAK</tt>. Let <tt>P</tt> be the output key from the <tt>PSBT_IN_WITNESS_UTXO</tt> scriptPubKey. If the Y coordinate of <tt>d·G</tt> is odd (i.e. does not match the X-only output key <tt>P</tt>), the Signer must negate <tt>d</tt>.

The Signer must verify that the X coordinate of <tt>d·G</tt> equals <tt>P</tt>. If they are not equal, the Signer must fail, as the tweak does not correspond to the spent output.<ref name="why_verify_tweak">''' Why must the Signer verify the tweak?''' The tweak is provided by the Updater and could be incorrect, either through error or malice. Without verification, the Signer would produce a valid Schnorr signature for a key it does not control, which could be used to steal funds. Verifying that the tweaked key matches the output key ensures the Signer is signing for the expected output.</ref>

The Signer must produce a BIP 340 Schnorr signature using the private key <tt>d</tt> and set the result in the <tt>PSBT_IN_TAP_KEY_SIG</tt> field as defined in BIP 371.

==== Finalizer ====

For each input that has a <tt>PSBT_IN_SP_TWEAK</tt> field set, the Finalizer must verify that a <tt>PSBT_IN_TAP_KEY_SIG</tt> field is present. If not, the input is not fully signed and cannot be finalized.

The Finalizer must construct the <tt>PSBT_IN_FINAL_SCRIPTWITNESS</tt> containing the single witness element from <tt>PSBT_IN_TAP_KEY_SIG</tt>, as per the BIP 341 key path spending rule. The Finalizer must then remove the <tt>PSBT_IN_SP_TWEAK</tt>, <tt>PSBT_IN_SP_SPEND_BIP32_DERIVATION</tt>, <tt>PSBT_IN_TAP_KEY_SIG</tt>, and <tt>PSBT_IN_WITNESS_UTXO</tt> fields.

Copy link
Contributor Author

@nymius nymius Mar 6, 2026

Choose a reason for hiding this comment

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

Agree.

Some lights on my thought process:
I followed BIP 370 approach for this, and it left all this unspecified as it relies mainly in BIP 341.
I thought we could rely back in BIP 352 too.

This was clearly an oversight.

@nymius nymius force-pushed the bip-spending-silent-payments-outputs-with-psbts branch from 75b7922 to c4b7f50 Compare March 6, 2026 20:11
@nymius
Copy link
Contributor Author

nymius commented Mar 6, 2026

Thanks for the thorough review @craigraw, much appreciated! I will leave it up to you to decide if the conversations are resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

New BIP PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants