Skip to content

Instantly share code, notes, and snippets.

@nothingmuch
Last active December 29, 2021 16:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nothingmuch/652f3a98089a0600637eadab738b2d6a to your computer and use it in GitHub Desktop.
Save nothingmuch/652f3a98089a0600637eadab738b2d6a to your computer and use it in GitHub Desktop.

    BIP: ????
    Title: Change forwarding
    Author: Yuval Kogman <nothingmuch@woobling.org>
    Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-????
    Status: Draft
    Type: Informational
    Created: 2018-11-05
    License: CC0-1.0
             GNU-All-Permissive

Table of Contents

Abstract

This document proposes a method for configuring BIP32 capable wallets in order to improve UTXO handling for non privacy/fungibility oriented wallets, by forwarding change outputs to a privacy preserving wallet.

Definitions

  • Forwarding wallet - any BIP32 capable wallet for day to day usage, for instance a hot wallet or special purpose application with embedded wallet (e.g. bisq, open bazaar, protip.is), extended with the functionality described in this document.
  • Fungibility wallet - any BIP32 capable wallet with privacy and fungibility features, in particular mixing (e.g. join market, wasabi)

Motivation

Different BIP32 capable wallets have been designed with various use cases in mind. Many of these (especially mobile wallets) lack good controls over the outputs being spent, and fewer still are focused on maintaining good privacy and fungibility. This creates the potential for inadvertently linking otherwise unrelated transactions when change outputs are used as inputs to subsequent transactions.

By adding the ability to forward all change outputs from such wallets directly to a branch of the BIP44 account hierarchy of a specializing mixing wallet, accidental linking due to human error or naive coin selection can be prevented. If UTXOs of the forwarding wallet can be assumed to be fungible, transaction independence can be maintained without special coin selection functionality since each subset of outputs can only be used by the wallet exactly once, and none of the resulting outputs are directly usable by the forwarding wallet. Those change outputs can subsequently be mixed and then redistributed to the forwarding wallet(s), preserving the validity of fungibility assumptions.

Specification

Fungibility Wallet Account Hierarchy

BIP32 describes the "Unsecure money receiver" role, which derives addresses using the public extended key for a specific chain. The forwarding wallet will function as an unsecure money receiver for the fungibility wallet.

BIP44 recommends separate non-hardened derivation for receiving (external) and change (internal) address chains, created as children hardened account paths. Separate hardened accounts should therefore be created, one for each forwarding wallet, with the external non-hardened chain, denoted m below, being exported using the following serialization format.

Serialization Format (TBD)

In order to ensure that the fungibility wallet can recognize spendable outputs generated by the forwarding wallet, both wallets must agree on the script derivation for a given public key in the address chain.

The BIP32 serialization format can therefore be ammended by the fungibility wallet with additional information using one of the following options:

  • SHA256( scriptPubKeym / 0 ) - allows arbitrary scripts/addresses, open for extension, multisig possible. Electrum protocol uses SHA256 but HMAC_SHA512(scriptPubKeym / 0, xpub) could also be used. Simplest to implement for forwarding wallets (go/no-go during setup based on existing address derivation).
  • SLIP32/SLIP132 or Electrum style version bytes - electrum also mentions but doesn't specify standard multsig version bytes, compact, only supports fixed script/address formats
  • miniscript
  • BIP124 templates - encoding/serialization format is still TODO, would allow arbitrary scripts, could in principle be parameterized over multiple xpubs to derive multisig scripts, relatively complex
  • BIP178 version bytes - fixed script formats, compact, no standard multisig, intended for WIF keys (mainly included for completeness)

Forwarding Wallet Setup

In the forwarding wallet, an additional configuration option should be provided which overrides the standard change internal address chain.

The configuration value must only be accepted if the forwarding wallet is capable of deriving a matching script as specified by the fungibility wallet.

Rationale

(note: This section makes the assumption that SHA256(scriptPubKey) is the preferred option for the serialization format which is still TBD. However, this is not clearly the case, primarily because version bytes approach is already prevalent, and the hashes are significantly less compact. On the other hand SLIP-0032 style extended public keys can lead to non fail-safe behaviour if the two wallets differ in their interpretation of the version bytes, and the derivation sub-path is only specified by convention. BIP124 templates are still not fully specified, and would require forwarding wallets to construct scripts differently, instead of just verifying that the fungibility wallet recognizes scripts of a form they already implement)

This proposal aims to improve interoperability of less coupled wallet implementations, specifically in a way that ensures that forwarding wallet transactions utilize separate master seeds in their inputs and outputs, under the assumption that the master seed used for the outputs is managed by specialized fungibility wallet.

Public extended keys are already in common use, though their main application has been to protect key material, and this typically assumes a high degree of coupling between the implementation of the watching wallet and the signing wallet, and that address chains derive from a single master seed.

Furthermore, since improving fungibility through interoperability is the main goal, the changes required in order to add forwarding capabilities to existing wallets should be minimal and leave little room for implementation error (no ambiguity with respect either the derivation path or the script being used).

Considerations

Ensuring Proper Mixing

Any non-fungible coins sent to the forwarding wallet are in no way protected by this setup, so the fungibility wallet must first be used correctly to ensure fungibility.

Secondly, subset sum analysis could still be performed on the change outputs used as inputs into mixing transactions, potentially linking pre-mix transactions. This concern can be alleviated by mixing in larger batches but is otherwise beyond the scope of this document.

Forwarding Wallet Implementation

Code Changes

This proposal is designed to minimize the required changes to forwarding wallets.

When creating change outputs, the only required change should be the switch to an address chain based on a public key instead of the wallet's regular account hierachy. If change forwarding is not configured, the same code path can still be used to derive change addresses from the forwarding wallet's account hierarchy using public child key derivation.

Most of the complexity of any changes is expected to be in the configuration and balance UIs.

Displaying Balances

Since change outputs become unspendable, forwarding wallets should convey to the user that after a payment is made the usable balance may decrease by more than the payment amount. Forwarding wallets can still display balances from the unspendable address chain (e.g. as "locked" balances) similar to watching wallets.

Fungibility Wallet Implementation

The fungibility wallet should allow exporting of different forms of public extended keys, but only for its supported script/address types, to avoid loss of funds. If multiple options are available the user can manually select which type to use, or leave that choice up to the forwarding wallet.

The fungibility wallet should keep track of exported keys and use separate hardened account derivation paths for different forwarding wallets, to avoid address reuse when different forwarding wallets are used concurrently. To ensure account discovery when recovering from seed using another wallet in accordance with BIP44 recommendations, the receiving wallet should only export new accounts if the previous account index has a transaction history, and may create a transaction that utilizes the first address in the chain before exporting.

Examples

We can consider two example scenarios, though technically one is just a special case of the other:

  • Wallet has one large UTXO
  • Wallet has multiple UTXOs of uniform or varying size

Unintended Linking

When a wallet has a single large UTXO and a payment is made, a transaction with a single change output will typically be created, effectively returning to the starting condition.

The resulting transaction graph might look something like the following, where edges terminating in x denote fungible outputs, o denotes likely tainted outputs, and ... denotes outputs controlled by other parties:

    x--initial output--> TX_1--+--change--> TX_2--+--change--> TX_3--+--change---o
                               |                  |                  |
                               +--payment--...    +--payment--...    +--payment--...

With more fragmented UTXOs the situation might look more like:

    x--+
       |
    x--+--> TX_1--+--change---o
       |          |
    x--+          +--payment--...
    
    
    x--+                  x--+
       |                     |
    x--+--> TX_2--+--change--+--> TX_3--+--change---o
                  |                     |
                  +--payment--...       +--payment--...

In addition to coin selection features, BIP69 and BIP126 can be used to make inputs less distinguishable payment vs. change outputs, but we assume the forwarding wallets do not necessarily make such considerations.

Linking Prevention

By interspersing payment transactions with mixing transactions, the resulting transaction graph is harder to analyze, even if the forwarding wallet makes no considerations when constructing inputs, since the property that all spendable UTXOs are unlinkable is preserved by the mixing wallet.

Note that in the following diagrams mixing stages may represent multiple transactions. Additionally, change outputs of all transactions are only spendable by the mixing wallet, and at the end of the following sequence the forwarding wallet balance is 0, i.e. fungible outputs (x) are only spendable by the forwarding wallet, and tainted outputs (o) are only spendable by the mixing wallet:

                                                            :
                                                            |
                          :           :     ...--3rd party--+           :
                          |           |                     |           |
          ...--3rd party--+           +--3rd party--...     |           +--3rd party--...
                          |           |                     |           |
    x--> TX_1--+--change--+--> MIX_1--+--> TX_2--+--change--+--> MIX_2--+--> TX_3--+--change---o
               |                                 |                                 |
               +--payment--...                   +--payment--...                   +--payment--...

Similarly with higher UTXO fragmentation:

                             :           :
                             |           |
    x--+     ...--3rd party--+           +--3rd party--...
       |                     |           |
    x--+--> TX_1--+--change--+--> MIX_1--+--mixed------x
       |          |
    x--+          +--payment--...

                             :           :
                             |           |
    x--+     ...--3rd party--+           +--3rd party--...     
       |                     |           |
    x--+--> TX_2--+--change--+--> MIX_2--+--mixed------x
                  |
                  +--payment--...       

    x--+          
       |
    x--+--> TX_3--+--change---o
                  |
                  +--payment--...

Test Vectors (TODO)

This section will be added pending final decision on the preferrable serialization format(s).

@Shabnam-Mir
Copy link

I have three questions about your interesting proposal. I would be so grateful if you answer me. First, as you mentioned your proposal is designed to minimize the required changes to forwarding wallets. How does your proposal minimize changes?
My second question is about mixing. Does fungibility wallet interact with mixing services to do mixing? If yes, which mixing service do you prefer?
And my last question is about something that @LaurentMT said. He said "mixing step creates a pattern which, at the level of a single transaction, allows to identify the payment output from the change output with almost 100% certainty." As far as I understood change output is sent to fungibility wallet and pass through multiple mixing transactions. Is this the something that determines which output is change output?

@nothingmuch
Copy link
Author

First, as you mentioned your proposal is designed to minimize the required changes to forwarding wallets. How does your proposal minimize changes?

Most BIP32 code I've seen do key or address derivation in a fairly general way, so the main change to the transaction building should just be dependency injection (instantiating an address chain separate from the one that is built from the wallet seed), and apart from this change everything else should be identical (same script/transaction structure).

The UI for the setup phase is more complex to implement, as that would require additional interfaces and new code functionality, but that too can reuse the change derivation code to ensure compatibility.

Compared to more comprehensive functionality like BIP47, or a specific transaction format, and based on my familiarity with wallet code (mostly reading bitcoinj based wallets), this seems like a relatively low complexity change.

My second question is about mixing. Does fungibility wallet interact with mixing services to do mixing? If yes, which mixing service do you prefer?

Right now I think the most appropriate implementation of a fungibility wallet is JoinMarket in tumbler mode.

I have also been working on some proposed changes to zerolink which if implemented would make Wasabi and Samourai appropriate for the kind of mixing I'm suggesting.

Apart from these I am not aware of any fungibility oriented wallets, from the point of view of this proposal I treated it as a black box. However, as @LaurentMT suggested, I should better qualify what I mean. I've been putting off revising this for now, as I've been focusing on some other things (and in general I find it much easier to write spaced out in time), so in the next iteration of this document I will try and clarify what criteria a fungibility wallet should meet in order to fulfill this role.

Secondly, I don't think this is the only use case for this specific proposal, since in terms of the technical details it's really just a way of checking and configuring two BIP32 wallets to share a public chain, it might also be useful for other use cases (e.g. configuring a watching wallet like sentinel or electrum personal server, or setting up something to receive payments directly to cold storage). This lack of clarity is another deficiency in the scope of the document that I'd like to improve.

And my last question is about something that @LaurentMT said. He said "mixing step creates a pattern which, at the level of a single transaction, allows to identify the payment output from the change output with almost 100% certainty." As far as I understood change output is sent to fungibility wallet and pass through multiple mixing transactions. Is this the something that determines which output is change output?

Considering just a single transaction, it should not be possible to distinguish, given that the script format of the forwarding wallet is retained, apart from the specific public key nothing is different.

However, if these change outputs are then directly used in coinjoin transactions but the payment outputs are not, this creates a pattern can be used to infer which outputs are change outputs and which aren't.

My assumption was that this kind of thing would happen anyway in wallets with no coin control, but instead of the change outputs being coinjoined afterwards, they would just be used as inputs to transactions of the same kind, so not just identifiable as change, but also clustered. In the ideal case, if the receiver (Bob in the examples above) provides an address from a fungibility wallet too, and then the change output would only be identifiable if the transaction follows a specific format (cf. output ordering discussions, like BIP69 or ideas about randomized orders, and BIP126 for relevant discussions)

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