Skip to content

Instantly share code, notes, and snippets.

@andrewtoth
Last active June 30, 2024 09:09
Show Gist options
  • Save andrewtoth/dc26f683010cd53aca8e477504c49260 to your computer and use it in GitHub Desktop.
Save andrewtoth/dc26f683010cd53aca8e477504c49260 to your computer and use it in GitHub Desktop.

  BIP: TBD
  Layer: Applications
  Title: PSBT Version 3
  Author: Andrew Toth <andrewstoth@gmail.com>
          josibake <josibake@protonmail.com>
  Comments-Summary: No comments yet.
  Comments-URI: TBD
  Status: Draft
  Type: Standards Track
  Created: 2024-05-14
  License: BSD-2-Clause

Table of Contents

Introduction

Abstract

This document proposes a third version of the Partially Signed Bitcoin Transaction format described in BIP 174 and BIP 370 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 BIP 370 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. There also must not be any inputs that use SIGHASH_ANYONECANPAY or have a scriptPubKey with Segwit version > 1. PSBT Version 3 is intended to rectify this problem.

Specification

PSBT Version 3 (PSBTv3) specifies new fields, new field inclusion/exclusion requirements, and additional bits in an existing bitfield field.

PSBT_GLOBAL_TX_MODIFIABLE may be included in PSBTv3, in which case the following bits are used: Bit 3 is the Silent Payments Modifiable Flag, set to 1 to indicate whether silent payment outputs may be added. Bit 4 is the Has Silent Payments Flag, set to 1 to indicate if any silent payment outputs have been added. Bit 4 indicates that the Constructor may not add any inputs either with SIGHASH_ANYONECANPAY or spending an output with Segwit version > 1 (TODO: How does constructor know this?).

PSBT_OUT_SCRIPT is modified to be optional for outputs in PSBT Version 3. If this field is not included in the output, then the field PSBT_OUT_SILENT_PAYMENT_CODE must be included.

The new per-output types for PSBT Version 3 are defined as follows:

Name <keytype> <keydata> <keydata> Description <valuedata> <valuedata> Description Versions Requiring Inclusion Versions Requiring Exclusion Versions Allowing Inclusion
Silent Payment Data PSBT_OUT_SILENT_PAYMENT_CODE = 0x08 None No key data <67-byte data> 67 bytes representing the Silent Payment Code. The first byte is the silent payment version. The next 33 bytes are the scan public key, and the following 33 bytes are the spend public key. 0, 2 3
Silent Payment DLEQ Proof PSBT_OUT_SILENT_PAYMENT_DLEQ_PROOF = 0x09 <compact size uint number of indexes> <32-bit little endian uint index>* The set of indexes of the inputs that this proof covers. <967-byte proof> A proof generated by a Signer used by other entities to generate and verify the output script for the silent payment code. Used by entities which don't have access to all private keys used in the shared secret deriviation. 0, 2 3

Unique Identification

PSBTv3s can be uniquely identified the same way as PSBTv2s, except when including silent payment outputs. For PSBTv3, all silent payment outputs must use the PSBT_OUT_SILENT_PAYMENT_CODE instead of PSBT_OUT_SCRIPT as the output script when creating the unsigned transaction used for unique identification.

Roles

PSBTv3 modifies some existing roles.

Creator

The Creator must do everything that is done in PSBTv2, except that the PSBT version is set to 3.

Additionally to PSBTv2, the Creator must also set the Silent Payments Modifiable and Has Silent Payments flags appropriately.

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_SILENT_PAYMENT_CODE set.

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

Inputs spending an output with Segwit version > 1 (TODO: How does constructor know this?) may only be added if the Has Silent Payments flag is False. Outputs with PSBT_OUT_SILENT_PAYMENT_CODE set may only be added if the Silent Payments Modifiable flag is True.

If an input is added that spends an output with Segwit version > 1 (TODO: How does constructor know this?), the Silent Payments Modifiable Flag must be set to False. If an output is added with PSBT_OUT_SILENT_PAYMENT_CODE, the Has Silent Payments Flag must be set to True.

Updater

For PSBTv3, the Updater must follow these additional rules: The PSBT_IN_SIGHASH_TYPE for an input may only add the sighash type SIGHASH_ANYONECANPAY if the Has Silent Payments flag is False. If the sighash type SIGHASH_ANYONECANPAY is added to an input, the Silent Payments Modifiable flag must be set to False.

Signer

All rules must be followed from PSBTv2 for this role, in addition to the following:

The Signer should compute a DLEQ proof for each output that has PSBT_OUT_SILENT_PAYMENT_CODE using all inputs it has the private key for. The Signer should compute and set all missing PSBT_OUT_SCRIPT using its own private keys and all PSBT_OUT_SILENT_PAYMENT_DLEQ_PROOFs. If the Signer adds any DLEQ proofs or sets any missing PSBT_OUT_SCRIPTs, it must set the Inputs Modifiable flag to False.

If signing a SIGHASH_SINGLE input and the corresponding output does not have PSBT_OUT_SCRIPT set, the Signer must fail. If signing an input that is not SIGHASH_NONE or SIGHASH_SINGLE and any output does not have PSBT_OUT_SCRIPT set, the Signer must fail. If signing an input that is SIGHASH_SINGLE and the output corresponding to the input has PSBT_OUT_SILENT_PAYMENT_CODE set, the Signer should verify the PSBT_OUT_SCRIPT using all PSBT_OUT_SILENT_PAYMENT_DLEQ_PROOFs for that output. If signing an input that is not SIGHASH_NONE or SIGHASH_SINGLE, the Signer should verify the PSBT_OUT_SCRIPT using all PSBT_OUT_SILENT_PAYMENT_DLEQ_PROOFs for all outputs.

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 not provided and the Silent Payments Modifiable flag is set to True, the Signer may not sign with the sighash type SIGHASH_ANYONECANPAY. If a sighash type is not provided and the Signer signs with SIGHASH_ANYONECANPAY, the Silent Payments Modifiable flag must be set to False.

Computing the DLEQ Proof

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

Using the notation from BIP352

  • Let An be the sum of the public keys A of all eligible inputs the Signer has the private keys for
  • Let an be the sum of the private keys a of all eligible inputs the Signer has
  • Let C = an·Bscan
  • Let r be a 32-byte random nonce generated by the Signer
  • Let R1 = r·G
  • Let R2 = r·Bscan
  • Let e = SHA256(serP(R1) || serP(R2) || serP(An) || serP(C))
  • Let s = r + e·an
Set the PSBT_OUT_SILENT_PAYMENT_DLEQ_PROOF for the set of all eligible inputs the Signer has private keys for as serP(C) || ser256(e) || ser256(s).

Verifying the DLEQ Proof

For each output, 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.

Using the notation from BIP352

  • Let An be the sum of the public keys A of all inputs covered by the proof
  • Let proof be the data in PSBT_OUT_SILENT_PAYMENT_DLEQ_PROOF
  • Let C = proof[0:33]
  • Let e = proof[33:65]
  • Let s = proof[65:97]
  • Let R1 = s·G - e·An
  • Let R2 = s·Bscan - e·C
Verify that e == SHA256(serP(R1) || serP(R2) || serP(An) || serP(C)), otherwise fail.

Computing the Output Scripts

Compute the PSBT_OUT_SCRIPT using the procedure in BIP352 but substituting a·Bscan with the sum of all Cs for all proofs covering all eligible inputs for that output. If the proofs for any output do not cover all inputs exactly once with no overlap, fail computing the output scripts.

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.

Transaction Extractor

For PSBTv3s, the transaction extractor should verify all output scripts computed by silent payment codes are correct using the DLEQ proofs, otherwise fail.

Backwards Compatibility

PSBTv3 is backwards compatible with PSBTv2 if the Has Silent Payments flag is set to False or PSBT_GLOBAL_TX_MODIFIABLE is not present and no silent payment outputs have been added. Otherwise it is not backwards compatible.

Test Vectors

Todo

Rationale

    Reference implementation

    Todo

    @real-or-random
    Copy link

    real-or-random commented Jun 22, 2024

    Hi, I took a brief look at the DLEQ proof. Some minor comments:

    • It will be good practice to use a tagged hash as in BIP340.
    • It will be even better practice to derive r deterministically from the inputs and the secret, or even better using synthetic randomness as in BIP340. (Feel free to steal from BIP340). This will also make it easier to implement for libraries which already have BIP340.
    • I know it's a bit more work, but I think it will be nice to have the DLEQ proof in a separate BIP. DLEQ proofs are a nice tool that are useful in many different contexts and other protocols. Having them defined independently of a PSBT extension will make the spec reusable in applications.

    @andrewtoth
    Copy link
    Author

    @real-or-random
    Copy link

    Nice. I haven't read every single line, but looks exactly like what I've asked for!

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