Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BIP375: Sending Silent Payments in PSBTs #1687

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
196 changes: 196 additions & 0 deletions bip-PSBT-SP.mediawiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
<pre>
BIP: ?
Copy link
Member

@jonatack jonatack Jan 8, 2025

Choose a reason for hiding this comment

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

Please update here with 375, add an equivalent README entry, and update the Created field to today's date.

Layer: Applications
Title: Sending Silent Payments with PSBTs
Author: Andrew Toth <[email protected]>
Ava Chow <[email protected]>
josibake <[email protected]>
Comments-Summary: No comments yet.
Comments-URI: TBD
Status: Draft
Type: Standards Track
Created: 2024-05-14
License: BSD-2-Clause
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
Post-History: https://groups.google.com/g/bitcoindev/c/5G5wzqUXyk4
Requires: 352, 370
</pre>

==Introduction==

===Abstract===

This document proposes additional fields and updated role responsibilities for BIP370 PSBTv2
which adds support for sending to silent payments as described in BIP352.

===Copyright===

This BIP is licensed under the 2-clause BSD license.

===Motivation===

Partially Signed Bitcoin Transaction Version 2 as described in BIP370 is not compatible with sending to silent payments as described in BIP352.
In particular, the output script of a silent payment cannot be computed until after all transaction inputs have been added.
Additionally, the silent payment outputs computed by a signer must be verifiable by other entities, otherwise funds could be sent to an incorrect output script.
Therefore, new fields and role responsibilities must be added to carry, compute, and verify the silent payment data.

==Specification==

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

The new global types are defined as follows:

{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Silent Payment Global ECDH Share
| <tt>PSBT_GLOBAL_SP_ECDH_SHARE = 0x07</tt>
| <tt><33 byte scan key> <36 byte outpoint>*</tt>
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
| The scan key and a list of outpoints corresponding to the prevouts of the inputs that this ECDH share is for. The outpoints are composed of a 32 byte txid followed by a 32-bit little endian uint.
| <tt><33 byte share></tt>
| An ECDH share for a scan key, followed by a list of outpoints. The ECDH shared is computed with ''a * B_scan'', where ''a'' is the sum of all private keys of the inputs matching the list of outpoints, and ''B_scan'' is the scan key of a recipient.
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
|
| 0
| 2
|-
| Silent Payment Global DLEQ Proof
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
| <tt>PSBT_GLOBAL_SP_DLEQ = 0x08</tt>
| <tt><33 byte scan key> <36 byte outpoint>*</tt>
| The scan key and a list of outpoints corresponding to the prevouts of the inputs that this proof covers. The outpoints are composed of a 32 byte txid followed by a 32-bit little endian uint.
| <tt><64-byte proof></tt>
| A DLEQ proof computed for the matching ECDH share.

Choose a reason for hiding this comment

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

For a given set of outpoints, there are multiple relevant B_scan generators all of which share share the same a witness in their respective proofs. This could be one batch proof per SP output set, instead of per individual B_scan. Although only a single 64 byte proof per input set is required, the prover and verifier complexity is the same as n proofs, where n is the number of SP outputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this is a great insight, thank you!

Would it not also reduce the complexity, since it would only be one proof to verify after summing the B_scan generators instead of verifying each proof individually?

Choose a reason for hiding this comment

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

If you mean given $P = aG$, and scan keys $(B_i)_{i=1}^n$, it's possible to prove knowlege of $a$ in $Q = a (n^{-1} \sum B_i)$ where $n^{-1} \sum B_i$ is a public input, but I'm not sure this is sound / proving the same thing.

This reference (section 3.2.3.3) seems to suggest it isn't, see footnote 16 on page 73, there's additional delinearization terms which are similar to key cancellation mitigation (and afaict are amenable to Fiat-Shamir just the same). This is an improvement over my implied suggestion as batched multiplication be used, but it does not reduce it to a single multiplication. Admittedly I don't yet see how to actually attack soundness as a malicious prover, especially when the prover does not control the choice of the the B_scan keys.

The batch proof I'm familiar with involves having an R point per generator, so same structure as proposed in the DLEQ BIP, just generalized from 2 to n+1 verification equations. When the proof is encoded as the challenge and the response, the encoding the n+1 R points is implicit, so the size would still be 64 bytes and both prover and verifier work is concretely reduced (~half the verification equations, and a shared challenge hash), but not asymptotically as the total work is still linear for both prover and verifier.

Copy link

@nothingmuch nothingmuch Nov 18, 2024

Choose a reason for hiding this comment

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

Using the mentioned protocol, "RME-based common exponent Schnorr protocol" (Henry14 3.2.3.3), the verifier performs 2+k ECC mults per proof, where k is the number of silent payment outputs, but the k mults can be shared for a batch of proofs, which large transactions can be a significant improvement in verifier complexity.

Compared to this protocol the strawman protocol I described in the previous comment is broken in two ways, not just one:

  • two verification equations are needed, instead of only one (section 4.2 describes a lattice basis attack on soundness since the prover's responses are undetermined)
  • de-linearization (or in the multiplicative terms of Henry14, RME) is needed for soundness as well (see section 3.1.4.3)

In a non-interactive setting, the t_i terms of the random linear combination is generated by hashing.

If $t_i = H(B_1, B_2, \dots, B_k)$ ($B_i$ is supposed to be {B_{scan}}_i but that apparently isn't in github's latex regex =P) the $k$ proofs would share the same delinearized sum $\sum_{i=1}^k t_i B_i$, which appears as a term in the 2nd verification equation. This reduces $k^2$ ECC mults to $k$ (but asymptotically is the same because of other side of the equation still has a $\sum_{i=1}^{k} t_i S_i$ term where $S_i = aB_i$ is a public input).

Unfortunately the full set of SP_V0_INFO fields to be finalized before DLEQ proofs can be computed in that case, but if I understand Lemma 3.5 I think the $t_i$ values used for this can be derived as $t_i = H(B_i)$ without destroying the proof of soundness. If this is correct then this reduction in verifier computation could be applied to batch-verify whatever $k$ batch-DLEQs, but number of roundtrips is not reduced because new proofs would be needed for the new outputs, and verifiers would need to be given explicit subsets of the outputs for each batch proof indicating what it covers, instead of being able to construct the proof statements implicitly from the set of all SP_V0_INFO fields, so it's not clear that this is a meaningful improvement over hashing all of the $B_i$s to delinearize.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure the added complexity is worth it to add this.

|
| 0
| 2
|}

One new per-output type is defined as follows:

{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Silent Payment Data
| <tt>PSBT_OUT_SP_V0_INFO = 0x08</tt>
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
| None
| No key data
| <tt><33 byte scan key> <33 byte spend key></tt>
| The scan and spend public keys from the silent payments address.
|
| 0
| 2
|}

<tt>PSBT_OUT_SCRIPT</tt> is modified to be optional for outputs in silent payments capable PSBTs. If this field is not included in the output, then the field PSBT_OUT_SP_V0_INFO must be included.
If a PSBT_OUT_SCRIPT is not present for an output, then that output is being sent to a silent payment address represented by PSBT_OUT_SP_V0_INFO but the script has not yet been computed.
If both PSBT_OUT_SCRIPT and PSBT_OUT_SP_V0_INFO are present for an output, then the PSBT_OUT_SCRIPT is the computed output script corresponding to the silent payment address in PSBT_OUT_SP_V0_INFO.
If only PSBT_OUT_SCRIPT is present for an output, then the output is not being sent to a silent payment address.

===Unique Identification===

Silent payment capable PSBTs can be uniquely identified the same way as PSBTv2s, except when including silent payment outputs. If an output contains the the PSBT_OUT_SP_V0_INFO field, it must use that field instead of PSBT_OUT_SCRIPT as the output script when creating the unsigned transaction used for unique identification.<ref name="why_use_sp_info_field"> ''' Why use PSBT_OUT_SP_V0_INFO when serializing for a unique identifier?''' Since the same silent payment capable PSBT is valid whether or not a PSBT_OUT_SCRIPT is included in an output that has PSBT_OUT_SP_V0_INFO set, using the PSBT_OUT_SCRIPT if present for the unique identifier will cause malleability. The identifier will be different depending on whether PSBT_OUT_SCRIPT is present, so always using PSBT_OUT_SP_V0_INFO if it exists makes sure the PSBT is always identified uniquely.</ref>
The PSBT_OUT_SP_V0_INFO should be serialized as a zero byte for the version, followed by the 33 bytes of the scan key and then 33 bytes for the spend key.


==Roles==

This document modifies some existing roles.

===Constructor===

All rules must be followed from PSBTv2 for this role, with the following exception:
When an output is added, it must have either PSBT_OUT_SCRIPT or PSBT_OUT_SP_V0_INFO, or both, set.
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved

Additionally to PSBTv2, the Constructor must also follow additional rules:

Inputs spending an output with script using Segwit version > 1 may only be added if there are no outputs with PSBT_OUT_SP_V0_INFO set.
Outputs with PSBT_OUT_SP_V0_INFO set may only be added if there are no inputs spending an output script using Segwit version > 1.
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved

===Updater===

====Change Detection====

Updaters may add two PSBT_OUT_BIP32_DERIVATION key-value-pairs with the corresponding derivation path of both the scan and spend keys. The Signer can then use these fields to verify that the silent payment code is change.

===Signer===

All rules must be followed from PSBTv2 for this role. If there are any outputs with PSBT_OUT_SP_V0_INFO set, then the following additional rules must also be adhered to:

If any input is spending an output with script using Segwit version > 1, the Signer must fail.

For all outputs with PSBT_OUT_SP_V0_INFO set, the Signer should:
* Compute and set an ECDH share and DLEQ proof using all inputs it has the private key for.
* Verify the DLEQ proofs for all inputs it does not have the private keys for.
* If all eligible inputs have an ECDH share, compute and set the PSBT_OUT_SCRIPT.

If the Signer sets any missing PSBT_OUT_SCRIPTs, it must set the Inputs Modifiable flag to False.

If any output does not have PSBT_OUT_SCRIPT set, the Signer must not yet add a signature.

Choose a reason for hiding this comment

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

IIUC, if it were not for this, blinding the SP_V0_INFO field would be technically be possible.

Since that would necessarily add another round of communication between the various entities, as only only updaters with access to the blinding keys could set the output.

A global flag to indicate whether the additional round is required might make sense?

This flag might have 3 values, indicating if blinding is not used (allowing signers to update outputs), optional (precluding that), or required in which case all outputs must have SP_V0_INFO, with dummy values used for non-SP outputs. "required" or "mandatory" blinding is a bit misleading, it's providing deniability as to which outputs use SP, not requiring SP and blinding actually be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it's this requirement, but the one a few lines up:
* If all eligible inputs have an ECDH share, compute and set the PSBT_OUT_SCRIPT.

We would need to only compute the output scripts for the non-blinded outputs.
Yes, if we want to hide which participants add an SP vs a regular taproot address entirely, we would need all outputs to have a dummy SP_V0_INFO and have everyone compute shares and proofs for them, even if they don't end up being used.


The Signer should additionally compute the silent payment addresses, optionally showing this data to the user instead of the computed segwit v1 addresses.

If a sighash type is provided and there are silent payment outputs present, the signer must fail if the sighash type is not SIGHASH_ALL.
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
If a sighash type is not provided and there are silent payment outputs present, the signer must sign using SIGHASH_ALL.<ref name="why_use_sighash_all"> ''' Why use only SIGHASH_ALL?''' BIP352 allows signing with SIGHASH_NONE and SIGHASH_SINGLE. However, silent payment capable PSBTs compute the output scripts deterministically based on the number and position of silent payment codes with the same scan key. SIGHASH_NONE and SIGHASH_SINGLE allow changing the amount or position of silent payment codes with the same scan and spend keys, which would invalidate computed output scripts.</ref>

====Computing the DLEQ Proof====

For each output with PSBT_OUT_SP_V0_INFO set, the Signer may generate a proof for other entities to generate the output scripts and verify that the output scripts were generated correctly.

Generate a global ECDH share for each scan key ''B<sub>scan</sub>'' and all eligible inputs the Signer has private keys for as follows:

Using the notation from [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#specification BIP352]

* Let ''A<sub>n</sub>'' be the sum of the public keys ''A'' of all eligible inputs
* Let ''a<sub>n</sub>'' be the sum of the private keys ''a'' of all eligible inputs
* Let ''C = a<sub>n</sub>·B<sub>scan</sub>''

Use a key ''B<sub>scan</sub>'' followed by a list of the outpoints of all eligible inputs.
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved

Set the value for the key of PSBT_GLOBAL_SP_ECDH_SHARE to ''C''.

Compute the DLEQ proof for ''C'' using ''a<sub>n</sub>'' and ''B<sub>scan</sub>''.
Set the value for the key of PSBT_GLOBAL_SP_DLEQ to the proof.

====Verifying the DLEQ Proof====

For each output with PSBT_OUT_SP_V0_INFO set, the Signer should verify the ECDH shares for all eligible inputs it does not have the private key for using the proofs provided by other Signers.

====Computing the Output Scripts====

Compute the PSBT_OUT_SCRIPT using the procedure in [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#user-content-Creating_outputs BIP352] but substituting ''a·B<sub>scan</sub>'' with the sum of all PSBT_GLOBAL_SP_ECDH_SHAREs for that scan key.
andrewtoth marked this conversation as resolved.
Show resolved Hide resolved
If there are multiple silent payment codes with the same scan key, sort the codes lexicographically in ascending order to determine the ordering of the ''k'' value.
If there are multiple silent payment codes with both the same scan and spend keys, sort the subgroup by output index in ascending order.

===Transaction Extractor===

For silent payment capable PSBTs, the transaction extractor should compute all output scripts for silent payment codes and verify they are correct using the ECDH shares and DLEQ proofs, otherwise fail.

==Backwards Compatibility==

Silent payment capable PSBTs are backwards compatible with PSBTv2 once all outputs have PSBT_OUT_SCRIPT set. Otherwise they are not backwards compatible.

==Test Vectors==

Todo

==Rationale==

<references/>

==Reference implementation==

Todo
Loading