Skip to content

Instantly share code, notes, and snippets.

@nymius
Last active January 19, 2026 17:34
Show Gist options
  • Select an option

  • Save nymius/b3dd0b8a08c6735d617e6216b73c4260 to your computer and use it in GitHub Desktop.

Select an option

Save nymius/b3dd0b8a08c6735d617e6216b73c4260 to your computer and use it in GitHub Desktop.
Silent Payments PSBT spending

PSBT_IN_SP_TWEAK for spending silent payment outputs

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.

Motivation

BIPs 352 specify silent payments protocol, which provides a new way to create P2TR outputs and spend them. The existing PSBT fields are unable to support silent payments without changes, due to the new method by which outputs are created. BIP 375 and complementary BIP 374 specify how to create outputs locked with silent payment keys using PSBTs. But they don't specify how to unlock these outputs in a transaction. Therefore a new field must be defined to allow PSBTs to carry the information necessary for tweaking taproot keys without following the BIP 340 tagging scheme.

Specification

The new per-input type is defined as follows:

Name <keytype> <keydata> <keydata>
Description
<valuedata> <valuedata>
Description
<Versions Requiring Inlusion> <Versions Requiring Exclusion> <Versions Allowing Inclusion>
Silent Payment Tweak
PSBT_IN_SP_TWEAK = 0x1f None No key data <32-byte hash> A 32 byte raw tweak. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed. 0 2

Where the <32-byte-hash> is computed per BIP 3521 as:

$$hash_{BIP0352/SharedSecret}(ser_{P}(\text{\it{ecdh\_shared\_secret}}) \| ser_{32}(k))$$

Rationale

On PSBTs, when spending non silent payment outputs, one can rely on the PSBT_IN_BIP32_DERIVATION or any of the allowed PSBT_IN_TAP_* combinations available to get the right private keys to sign for each input.

To spend silent payment outputs you have to combine the private key with the tweak obtained from the transaction corpus.

On PSBT there is no field prescribed for this raw tweaks. The PSBT_IN_BIP32_DERIVATION field cannot be used because its different nature, neither the PSBT_IN_TAP_MERKLE_ROOT field because of the tagged hash used for tweaking.

A change of the hash tag used for silent payments to TapTweak or something compatible with taproot tweaking wouldn't make sense. Although the raw tweak can be disguised as the tap tree merkle root for spending, at the moment of verifying change outputs, you need the full tap tree, and there would be none backing this fake merkle root.

The use of proprietary fields is possible but brittle, as one may end up having to perform extra lookups for keys that are not unified across implementations.

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

Backward Compatibility

This is a new field added to the existing PSBT format. Because PSBT is designed to be extensible, old software will ignore the new fields.

Test Vectors

To be added

Related Work

BIP 352, BIP 375, BIP 371

Considered questions

  • Why not scoping the field just for silent payments?

This would be similar to PSBT_IN_TAP_MERKLE_ROOT, and would rule out any other tweak using a different tagging scheme for the hash.

I'm not aware of the rational behind this decision, and looking at: BIP 371, BIP 340 and bitcoin/bitcoin#22558 (comment) couldn't come up with any.

I think this is too restrictive, as the tagging scheme is still applied at tweak generation, so there won't be collisions between the outputs generated by one or another tweaking scheme.

By allowing a raw hash, I'm allowing a quick addition of the tweak to the internal key, without having to perform any processing steps, and making this field available for signing of protocols using other tweaking schemes.

On the other hand, this is premature optimization, so at the end, it may be enough to just add a PSBT_IN_TAP_SP_TWEAK.

  • Why taproot uses the tag format in the way it uses it?

To avoid collisions in protocols using the same committed data like in the merkle root but doing something different than taproot.

  • Why BIP 371 specifies PSBT_IN_TAP_MERKLE_ROOT as the merkle root, instead of PSBT_IN_TAP_RAW_TWEAK?

Let's say there are two kinds of users: A, B. There is a single A user and there are multiple Bs. B users only know the merkle path of their spending branch. User A only knows about the internal private and public key. The B users can only provide the merkle root, as they cannot produce the final tweak hash because they don't have the internal key. For this case, the PSBT_IN_TAP_MERKLE_ROOT makes sense.

  • Should the spec specify how to combine the provided tweak with the private key to obtain the concrete private key and sign?

BIP 371 doesn't specify this and relies in BIP 340/341/342. I think this BIP could do the same and rely on BIP 352 for it.

  • Why adding a new field and not leaving the implementation to provide the prevouts to compute the shared secret by itself?

Once a silent payment UTXO is scanned, is easier to store the output together with the tweak that generated it. On the other side, passing the prevouts together with the PSBT to allow the computation of the tweaks puts a burden on the signer, that is computationally expensive.

References

CHANGELOG:

2nd revision:
  • Added answer to Why adding a new field and not leaving the implementation to provide the prevouts to compute the shared secret by itself?.
3th revision:
  • Replace keytype identifier TAP_RAW_TWEAK by PSBT_IN_SP_TWEAK (@craigraw): it is unclear how a hardware wallet will determine what the content of the field were in the first more general case, assuming different tweaking schemes available. And "PSBT fields are in general exactly specified as to the nature of the contents.".
  • Change keytype from 0x19 to 0x1f (@craigraw): BIP 375 added two new silent payment input fields PSBT_IN_SP_ECDH_SHARE = 0x1d and PSBT_IN_SP_DLEQ = 0x1e. Being available places for new fields immediately after them at the moment of this writing, and being semantically grouped under the same protocol, 0x1f is a better fit for the new field.
4th revision:
  • Changed title from PSBT_IN_TAP_RAW_TWEAK for spending silent payment outputs to PSBT_IN_SP_TWEAK for spending silent payment outputs.
5th revision:
  • Added CHANGELOG.
6th revision:
  • Grammar changes related to the number of fields added.
  • Phrasing changes.
  • Added reference to the calculus of the 32 byte hash included as the <valuedata> of the new field (@craigraw).

Footnotes

  1. https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki

@mohmmedzalep24
Copy link

التعديل المقترح يضيف وضوحاً مهماً في سياق إنفاق مخرجات الدفع الصامت باستخدام PSBT. استخدام الحقل PSBTINSP_TWEAK يبدو مناسباً من حيث التوافق مع BIP 352، ويعزز قابلية التوسع لبروتوكولات أخرى تعتمد على تعديلات Taproot. يُفضل توضيح العلاقة بين هذا الحقل وحقول BIP 370 بشكل أكثر تفصيلاً في قسم "الملخص" لتسهيل الفهم للمطورين الجدد.

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