LearnBitcoin

Bitcoin Dev Archive 2020

BIP-341: Committing to all scriptPubKeys in the signature message

13 messages, 29 Apr to 11 May 2020. Started by Andrew Kozlik.

Andrew Kozlik (3), Russell O'Connor (3), Jeremy Rubin (2), Greg Sanders, David A. Harding, Anthony Towns, Jonas Nick, Pieter Wuille

Permalink Original thread on gnusha.org

Andrew Kozlik permalink original

Hi everyone,

In the current draft of BIP-0341 [1] the signature message commits to the scriptPubKey of the output being spent by the input. I propose that the signature message should commit to the scriptPubKeys of *all* transaction inputs.

In certain applications like CoinJoin, a wallet has to deal with transactions containing external inputs. To calculate the actual amount that the user is spending, the wallet needs to reliably determine for each input whether it belongs to the wallet or not. Without such a mechanism an adversary can fool the wallet into displaying incorrect information about the amount being spent, which can result in theft of user funds [2].

In order to ascertain non-ownership of an input which is claimed to be external, the wallet needs the scriptPubKey of the previous output spent by this input. It must acquire the full transaction being spent and verify its hash against that which is given in the outpoint. This is an obstacle in the implementation of lightweight air-gapped wallets and hardware wallets in general. If the signature message would commit to the scriptPubKeys of all transaction inputs, then the wallet would only need to acquire the scriptPubKey of the output being spent without having to acquire and verify the hash of the entire previous transaction. If an attacker would provide an incorrect scriptPubKey, then that would cause the wallet to generate an invalid signature message.

Note that committing only to the scriptPubKey of the output being spent is insufficient for this application, because the scriptPubKeys which are needed to ascertain non-ownership of external inputs are precisely the ones that would not be included in any of the signature messages produced by the wallet.

The obvious way to implement this is to add another hash to the signature message: sha_scriptPubKeys (32): the SHA256 of the serialization of all scriptPubKeys of the previous outputs spent by this transaction.

Cheers, Andrew Kozlik

[1] https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message [2] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html

Jeremy Rubin in reply to Andrew Kozlik permalink original

Hi Andrew,

If you use SIGHASH_ALL it shall sign the COutPoints of all inputs which commit to the scriptPubKeys of the txn.

Thus the 341 hash doesn't need to sign any additional data.

As a metadata protocol you can provide all input transactions to check the scriptPubKeys.

Best,

Jeremy

Andrew Kozlik in reply to Jeremy Rubin permalink original

Hi Jeremy,

What you are saying is correct and I am not disputing that there is sufficient cryptographic commitment in the signature message. As I tried to explain, my proposal is about avoiding the need for the metadata protocol you speak of. Avoiding such a protocol has been a design goal in both BIP-143 [1, 2] and BIP-341 [3, 4], because having to acquire each of the transactions being spent in their entirety places a significant burden on offline signing devices.

Cheers, Andrew

[1] https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#motivation [2] https://bitcointalk.org/index.php?topic=181734.0 [3] https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-16 [4] https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-17

On Fri, May 1, 2020 at 8:56 AM Jeremy <jlrubin@mit•edu> wrote:

Quoted text (70 lines)
> Hi Andrew,
>
> If you use SIGHASH_ALL it shall sign the COutPoints of all inputs which
> commit to the scriptPubKeys of the txn.
>
> Thus the 341 hash doesn't need to sign any additional data.
>
> As a metadata protocol you can provide all input transactions to check the
> scriptPubKeys.
>
> Best,
>
> Jeremy
> --
> @JeremyRubin <https://twitter.com/JeremyRubin>
>
>
> On Thu, Apr 30, 2020 at 1:22 AM Andrew Kozlik via bitcoin-dev <
> bitcoin-dev@lists•linuxfoundation•org> wrote:
>
>> Hi everyone,
>>
>> In the current draft of BIP-0341 [1] the signature message commits to the
>> scriptPubKey of the output being spent by the input. I propose that the
>> signature message should commit to the scriptPubKeys of *all* transaction
>> inputs.
>>
>> In certain applications like CoinJoin, a wallet has to deal with
>> transactions containing external inputs. To calculate the actual amount
>> that the user is spending, the wallet needs to reliably determine for each
>> input whether it belongs to the wallet or not. Without such a mechanism an
>> adversary can fool the wallet into displaying incorrect information about
>> the amount being spent, which can result in theft of user funds [2].
>>
>> In order to ascertain non-ownership of an input which is claimed to be
>> external, the wallet needs the scriptPubKey of the previous output spent by
>> this input. It must acquire the full transaction being spent and verify its
>> hash against that which is given in the outpoint. This is an obstacle in
>> the implementation of lightweight air-gapped wallets and hardware wallets
>> in general. If the signature message would commit to the scriptPubKeys of
>> all transaction inputs, then the wallet would only need to acquire the
>> scriptPubKey of the output being spent without having to acquire and verify
>> the hash of the entire previous transaction. If an attacker would provide
>> an incorrect scriptPubKey, then that would cause the wallet to generate an
>> invalid signature message.
>>
>> Note that committing only to the scriptPubKey of the output being spent
>> is insufficient for this application, because the scriptPubKeys which are
>> needed to ascertain non-ownership of external inputs are precisely the ones
>> that would not be included in any of the signature messages produced by the
>> wallet.
>>
>> The obvious way to implement this is to add another hash to the signature
>> message:
>> sha_scriptPubKeys (32): the SHA256 of the serialization of all
>> scriptPubKeys of the previous outputs spent by this transaction.
>>
>> Cheers,
>> Andrew Kozlik
>>
>> [1]
>> https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
>> [2]
>> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html
>> _______________________________________________
>> bitcoin-dev mailing list
>> bitcoin-dev@lists•linuxfoundation•org
>> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>>
>
Russell O'Connor in reply to Andrew Kozlik permalink original

While I'm not entirely convinced yet that accertaining non-ownership of an input is a robust method of solving the problem here, I also see little reason not to amend BIP-341 as proposed. The ScriptPubKeys in question is already indirectly covered through the outpoints, so it is just a matter of optimization. Furthermore in the consensus code, the ScriptPubKeys are part of the UTXO data set, and it is already being retrieved as part of the transaction checking process, so it is readily available.

I'm not sure how much my opinion on the topic matters, but I did include this kind of functionality in my design for Simplicity on Elements, and I have been leaning towards adding this kind of functionality in my Bitcoin demo application of Simplicity.

Regarding specifics, I personally think it would be better to keep the hashes of the ScriptPubKeys separate from the hashes of the input values. This way anyone only interested in input values does not need to wade through what are, in principle, arbitrarily long ScriptPubKeys in order to check the input values (which each fixed size). To that end, I would also (and independently) propose separating the hashing of the output values from the output ScriptPubKeys in `sha_outputs` so again, applications interested only in summing the values of the outputs (for instance to compute fees) do not have to wade through those arbitrarily long ScriptPubKeys in the outputs.

On Thu, Apr 30, 2020 at 4:22 AM Andrew Kozlik via bitcoin-dev < bitcoin-dev@lists•linuxfoundation•org> wrote:

Quoted text (49 lines)
> Hi everyone,
>
> In the current draft of BIP-0341 [1] the signature message commits to the
> scriptPubKey of the output being spent by the input. I propose that the
> signature message should commit to the scriptPubKeys of *all* transaction
> inputs.
>
> In certain applications like CoinJoin, a wallet has to deal with
> transactions containing external inputs. To calculate the actual amount
> that the user is spending, the wallet needs to reliably determine for each
> input whether it belongs to the wallet or not. Without such a mechanism an
> adversary can fool the wallet into displaying incorrect information about
> the amount being spent, which can result in theft of user funds [2].
>
> In order to ascertain non-ownership of an input which is claimed to be
> external, the wallet needs the scriptPubKey of the previous output spent by
> this input. It must acquire the full transaction being spent and verify its
> hash against that which is given in the outpoint. This is an obstacle in
> the implementation of lightweight air-gapped wallets and hardware wallets
> in general. If the signature message would commit to the scriptPubKeys of
> all transaction inputs, then the wallet would only need to acquire the
> scriptPubKey of the output being spent without having to acquire and verify
> the hash of the entire previous transaction. If an attacker would provide
> an incorrect scriptPubKey, then that would cause the wallet to generate an
> invalid signature message.
>
> Note that committing only to the scriptPubKey of the output being spent is
> insufficient for this application, because the scriptPubKeys which are
> needed to ascertain non-ownership of external inputs are precisely the ones
> that would not be included in any of the signature messages produced by the
> wallet.
>
> The obvious way to implement this is to add another hash to the signature
> message:
> sha_scriptPubKeys (32): the SHA256 of the serialization of all
> scriptPubKeys of the previous outputs spent by this transaction.
>
> Cheers,
> Andrew Kozlik
>
> [1]
> https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
> [2]
> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation•org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>
Greg Sanders in reply to Russell O'Connor permalink original

For what it's worth this measure had been discussed as a lightweight way of informing offline signers if inputs were segwit or not for malleability analysis reasons. So there's at least a couple direct use-cases it seems.

On Fri, May 1, 2020, 8:23 AM Russell O'Connor via bitcoin-dev < bitcoin-dev@lists•linuxfoundation•org> wrote:

Quoted text (81 lines)
> While I'm not entirely convinced yet that accertaining non-ownership of an
> input is a robust method of solving the problem here, I also see little
> reason not to amend BIP-341 as proposed. The ScriptPubKeys in question is
> already indirectly covered through the outpoints, so it is just a matter of
> optimization.  Furthermore in the consensus code, the ScriptPubKeys are
> part of the UTXO data set, and it is already being retrieved as part of the
> transaction checking process, so it is readily available.
>
> I'm not sure how much my opinion on the topic matters, but I did include
> this kind of functionality in my design for Simplicity on Elements, and I
> have been leaning towards adding this kind of functionality in my Bitcoin
> demo application of Simplicity.
>
> Regarding specifics, I personally think it would be better to keep the
> hashes of the ScriptPubKeys separate from the hashes of the input values.
> This way anyone only interested in input values does not need to wade
> through what are, in principle, arbitrarily long ScriptPubKeys in order to
> check the input values (which each fixed size).  To that end, I would also
> (and independently) propose separating the hashing of the output values
> from the output ScriptPubKeys in `sha_outputs` so again, applications
> interested only in summing the values of the outputs (for instance to
> compute fees) do not have to wade through those arbitrarily long
> ScriptPubKeys in the outputs.
>
> On Thu, Apr 30, 2020 at 4:22 AM Andrew Kozlik via bitcoin-dev <
> bitcoin-dev@lists•linuxfoundation•org> wrote:
>
>> Hi everyone,
>>
>> In the current draft of BIP-0341 [1] the signature message commits to the
>> scriptPubKey of the output being spent by the input. I propose that the
>> signature message should commit to the scriptPubKeys of *all* transaction
>> inputs.
>>
>> In certain applications like CoinJoin, a wallet has to deal with
>> transactions containing external inputs. To calculate the actual amount
>> that the user is spending, the wallet needs to reliably determine for each
>> input whether it belongs to the wallet or not. Without such a mechanism an
>> adversary can fool the wallet into displaying incorrect information about
>> the amount being spent, which can result in theft of user funds [2].
>>
>> In order to ascertain non-ownership of an input which is claimed to be
>> external, the wallet needs the scriptPubKey of the previous output spent by
>> this input. It must acquire the full transaction being spent and verify its
>> hash against that which is given in the outpoint. This is an obstacle in
>> the implementation of lightweight air-gapped wallets and hardware wallets
>> in general. If the signature message would commit to the scriptPubKeys of
>> all transaction inputs, then the wallet would only need to acquire the
>> scriptPubKey of the output being spent without having to acquire and verify
>> the hash of the entire previous transaction. If an attacker would provide
>> an incorrect scriptPubKey, then that would cause the wallet to generate an
>> invalid signature message.
>>
>> Note that committing only to the scriptPubKey of the output being spent
>> is insufficient for this application, because the scriptPubKeys which are
>> needed to ascertain non-ownership of external inputs are precisely the ones
>> that would not be included in any of the signature messages produced by the
>> wallet.
>>
>> The obvious way to implement this is to add another hash to the signature
>> message:
>> sha_scriptPubKeys (32): the SHA256 of the serialization of all
>> scriptPubKeys of the previous outputs spent by this transaction.
>>
>> Cheers,
>> Andrew Kozlik
>>
>> [1]
>> https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
>> [2]
>> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html
>> _______________________________________________
>> bitcoin-dev mailing list
>> bitcoin-dev@lists•linuxfoundation•org
>> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>>
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation•org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>
Jeremy Rubin in reply to Greg Sanders permalink original

At the end of the day I don't really care that much I just prefer something that doesn't throw taproot in for another review cycle.

A side effect of this proposal is it would seem to make it not possible to produce a signature for a transaction without having access to the inputs. This is limiting for a number of cases where you don't care about that data. There are a litany of use cases where you don't want to have SIGHASH_ALL behavior, and having to sign the scriptpubkeys breaks that. So at the very least it should respect other flags.

I also don't really understand the exact attack. So you submit a transaction to the wallet asking them to sign input 10. They sign. They've committed to the signature being bound to the specific COutpoint and input index, so I don't see how they wouldn't be required to sign a second signature with the other output too? Is there an attack you can describe end-to-end relying on this behavior?

If you look at the TXID hash the vouts are one of the last fields serialized. this makes it possible (at least, I think) to do a midstate proof so that all you are providing is the hash midstate, and the relevant transaction output, the siblings after, and the locktime. So you get to skip all the input data, the witness data, and most of the output data.

This sort of data can easily go into the proprietary use (maybe becoming well defined if there's a standardization push) area in PSBT, so that hardware devices can get easy access to it. All they have to do to verify is to finalize the hash against that buffer and match to the correct input.

As an alternative proposal, I think you can just make a separate BIP for some new sigash flags that can be reviewed separately from taproot. There's a lot of value in investing in figuring out more granular controls over what the signature hash is you sign, which may have some exciting contracting implications!

David A. Harding in reply to Andrew Kozlik permalink original

On Wed, Apr 29, 2020 at 04:57:46PM +0200, Andrew Kozlik via bitcoin-dev wrote:

Quoted text (3 lines)
> In order to ascertain non-ownership of an input which is claimed to be
> external, the wallet needs the scriptPubKey of the previous output spent by
> this input.

A wallet can easily check whether a scriptPubKey contais a specific pubkey (as in P2PK/P2TR), but I think it's impractical for most wallets to check whether a scriptPubKey contains any of the possible ~two billion keys available in a specific BIP32 derivation path (and many wallets natively support multiple paths).

It would seem to me that checking a list of scriptPubKeys for wallet matches would require obtaining the BIP32 derivation paths for the corresponding keys, which would have to be provided by a trusted data source. If you trust that source, you could just trust them to tell you that none of the other inputs belong to your wallet.

Alternatively, there's the scheme described in the email you linked by Greg Saunders (with the scheme co-attributed to Andrew Poelstra), which seems reasonable to me.[1] It's only downside (AFAICT) is that it requires an extra one-way communication from a signing device to a coordinator. For a true offline signer, that can be annoying, but for an automated hardware wallet participating in coinjoins or LN, that doesn't seem too burdensome to me.

-Dave

[1] The scheme could be trivially tweaked to be compatible with BIP322
    generic signed messages, which is something that could become widely
    adopted (I hope) and so make supporting the scheme easier.
Anthony Towns in reply to Russell O'Connor permalink original

On Fri, May 01, 2020 at 08:23:07AM -0400, Russell O'Connor wrote:

Quoted text (2 lines)
> Regarding specifics, I personally think it would be better to keep the
> hashes of the ScriptPubKeys separate from the hashes of the input values.

I think Andrew's original suggestion achieves this:

Quoted text (5 lines)
>> The obvious way to implement this is to add another hash to the
>> signature message:
>>   sha_scriptPubKeys (32): the SHA256 of the serialization of all
>>   scriptPubKeys of the previous outputs spent by this
>>   transaction.

presumably with sha_scriptPubKeys' inclusion being conditional on hash_type not matching ANYONECANPAY.

We could possibly also make the "scriptPubKey" field dependent on hash_type matching ANYONECANPAY, making this not cost any more in serialised bytes per signature.

This would basically mean we're committing to each component of the UTXOs being spent:

  without ANYONECANPAY:
    sha_prevouts commits to the txid hashes and vout indexes (COutPoint)
    sha_amounts commits to the nValues (Coin.CTxOut.nValue)
    sha_scriptpubkeys commits to the scriptPubKey (Coin.CTxOut.scriptPubKey)
  with ANYONECANPAY it's the same but just for this input's prevout:
    outpoint
    amount
    scriptPubKey

except that we'd arguably still be missing:

    is this a coinbase output? (Coin.fCoinBase)
    what was the height of the coin? (Coin.nHeight)

Maybe committing to the coinbase flag would have some use, but committing to the height would make it hard to chain unconfirmed spends, so at least that part doesn't seem worth adding.

Quoted text (5 lines)
> I would also (and independently) propose
> separating the hashing of the output values from the output ScriptPubKeys in
> `sha_outputs` so again, applications interested only in summing the values of
> the outputs (for instance to compute fees) do not have to wade through those
> arbitrarily long ScriptPubKeys in the outputs.

If you didn't verify the output scriptPubKeys, you would *only* be able to care about fees since you couldn't verify where any of the funds went? And you'd only be able to say fees are "at least x", since they could be more if one of the scriptPubKeys turned out to be OP_TRUE eg. That might almost make sense for a transaction accelerator that's trying to increase the fees; but only if you were doing it for someone else's transaction (since otherwise you'd care about the output addresses) and only if you were happy to not receive any change? Seems like a pretty weird use case?

There's some prior discussion on this topic at:

http://www.erisian.com.au/taproot-bip-review/log-2020-03-04.html http://www.erisian.com.au/taproot-bip-review/log-2020-03-05.html

Cheers, aj

Russell O'Connor in reply to Anthony Towns permalink original
Quoted text (9 lines)
> If you didn't verify the output scriptPubKeys, you would *only* be able
> to care about fees since you couldn't verify where any of the funds went?
> And you'd only be able to say fees are "at least x", since they could be
> more if one of the scriptPubKeys turned out to be OP_TRUE eg. That might
> almost make sense for a transaction accelerator that's trying to increase
> the fees; but only if you were doing it for someone else's transaction
> (since otherwise you'd care about the output addresses) and only if you
> were happy to not receive any change? Seems like a pretty weird use case?
>

You are right of course. I was thinking of cases where you only care about where some of the outputs go but not all. But of course, even in that case you will need to wade through all of the output ScriptPubKeys anyways. The current design shares the hashOuputs value with the one computed with BIP-143, and that is a somewhat valuable property to keep.

Thanks for setting me straight.

Russell O'Connor in reply to Anthony Towns permalink original

On Sat, May 2, 2020 at 10:26 AM Anthony Towns <aj@erisian•com•au> wrote:

Quoted text (10 lines)
>
> except that we'd arguably still be missing:
>
>     is this a coinbase output? (Coin.fCoinBase)
>     what was the height of the coin? (Coin.nHeight)
>
> Maybe committing to the coinbase flag would have some use, but committing
> to the height would make it hard to chain unconfirmed spends, so at
> least that part doesn't seem worth adding.
>

To add to this point, the height of the coin is something that is *not* currently covered by any signature mode and including it would constitute a change of an entirely different caliber; a change that I would strongly caution against for your above reason and more.

The coinbase output flag is currently covered by the signature as the outpoint hash has the required information (its prevout index of 0xFFFFFFFF is only legal in a coinbase transaction). While I'm not particularly enthusiastic about making it easier to distinguish coinbase outputs from other outputs, and I worry a little about alternative designs for implementing the Bitcoin protocol where this information is not so readily available, I suppose I won't really oppose adding it. However, I don't think anyone is seriously proposing it. -

Andrew Kozlik in reply to Russell O'Connor permalink original
Quoted text (8 lines)
>
> A side effect of this proposal is it would seem to make it not possible to
> produce a signature for a transaction without having access to the inputs.
> This is limiting for a number of cases where you don't care about that
> data. There are a litany of use cases where you don't want to have
> SIGHASH_ALL behavior, and having to sign the scriptpubkeys breaks that. So
> at the very least it should respect other flags.
>

I agree, sha_scriptPubKeys should be included only if hash_type does not match SIGHASH_ANYONECANPAY. I am also sympathetic to aj's idea of making the scriptPubKey field dependent on hash_type matching SIGHASH_ANYONECANPAY.

I also don't really understand the exact attack. So you submit a

Quoted text (6 lines)
> transaction to the wallet asking them to sign input 10. They sign. They've
> committed to the signature being bound to the specific COutpoint and input
> index, so I don't see how they wouldn't be required to sign a second
> signature with the other output too? Is there an attack you can describe
> end-to-end relying on this behavior?
>

For example, in a CoinJoin transaction the attacker can construct a transaction with two inputs (in1, in2) of identical value and two outputs of identical value, one belonging to the user (user_out) and another belonging to the attacker (attacker_out). If such a transaction is sent to the hardware wallet twice with in1 marked as external the first time and in2 marked as external the second time, then the hardware wallet will display two signing requests to the user with spending amounts of in2 - user_out and in1 - user_out respectively. The user will think that they are signing two different CoinJoin transactions, while in reality they are signing two different inputs to a single transaction and sending half of the amount to the attacker.

As an alternative proposal, I think you can just make a separate BIP for

Quoted text (5 lines)
> some new sigash flags that can be reviewed separately from taproot. There's
> a lot of value in investing in figuring out more granular controls over
> what the signature hash is you sign, which may have some exciting
> contracting implications!
>

The proposal of adding sha_scriptPubKeys is just an optimization which is not intended to change what the signature message is committing to. Thus I don't see it as warranting a new sigash flag.

Alternatively, there's the scheme described in the email you linked by Greg

Quoted text (7 lines)
> Saunders (with the scheme co-attributed to Andrew Poelstra), which seems
> reasonable to me.[1]  It's only downside (AFAICT) is that it requires an
> extra one-way communication from a signing device to a coordinator.  For a
> true offline signer, that can be annoying, but for an automated hardware
> wallet participating in coinjoins or LN, that doesn't seem too burdensome
> to me.
>

Yes, I see this as the correct direction forward. Whatever the exact format of the ownership proof will be, the proof will need to be signed by the owner of the UTXO using BIP-0322 or something along those lines. So the scriptPubKey is needed to verify that signature.

Cheers, Andrew Kozlik

On Sat, May 2, 2020 at 11:16 PM Russell O'Connor <roconnor@blockstream•com> wrote:

Quoted text (30 lines)
> On Sat, May 2, 2020 at 10:26 AM Anthony Towns <aj@erisian•com•au> wrote:
>
>>
>> except that we'd arguably still be missing:
>>
>>     is this a coinbase output? (Coin.fCoinBase)
>>     what was the height of the coin? (Coin.nHeight)
>>
>> Maybe committing to the coinbase flag would have some use, but committing
>> to the height would make it hard to chain unconfirmed spends, so at
>> least that part doesn't seem worth adding.
>>
>
> To add to this point, the height of the coin is something that is *not*
> currently covered by any signature mode and including it would constitute a
> change of an entirely different  caliber; a change that I would strongly
> caution against for your above reason and more.
>
> The coinbase output flag is currently covered by the signature as the
> outpoint hash has the required information (its prevout index of 0xFFFFFFFF
> is only legal in a coinbase transaction).  While I'm not particularly
> enthusiastic about making it easier to distinguish coinbase outputs from
> other outputs, and I worry a little about alternative designs for
> implementing the Bitcoin protocol where this information is not so readily
> available, I suppose I won't really oppose adding it.  However, I don't
> think anyone is seriously proposing it.
>
>    -
>
>
Jonas Nick in reply to Andrew Kozlik permalink original

This is a reasonable suggestion. Committing to every spent scriptPubKey and therefore every element of the TxOut instead of just the amount makes sense conceptually. And it would be a small diff (~4 lines + rationale) compared to the current bip-taproot version.

As far aas I understand, coinjoin with offline signers would be substantially harder without this proposal. There is a WIP "SLIP" that helped me understand how the Proof of Ownership would work [0]. For every input, the offline signing device verifies a signature against the corresponding scriptPubKey. In order to obtain the correct scriptPubKey, sending the whole input transaction to the signing device is prohibitive when the available bandwidth is low (QR codes). The idea of only sending the transaction midstate along with the rest of to-be-hashed transaction data is an improvement, but still results in a lot of data (whole vout and witness stacks). Adding a new sighash flag that marks coinjoin transactions would be a step backwards fungibility-wise.

Thus, the same reasoning for for committing to the input values in the transaction digest to allow compact fee proofs would similarly apply the scriptPubKeys - with the only difference that coinjoins with offline signers are less common.

The downsides of this proposal seem to be limited. It requires additional review, but the BIP is only in the draft stage and should incorporate reasonable feedback. It does not invite further scope creep because the full TxOut would be already included. The costs to verifiers is only slightly increased using Anthony Town's suggested sighash change. Availability of the scriptPubKeys for signing devices does not seem to be an issue because the input amounts are already required. And if all inputs belong to the signing device, there's no additional data sent to the device.

[0] https://github.com/satoshilabs/slips/blob/slips-19-20-coinjoin-proofs/slip-0019.md

On 4/29/20 2:57 PM, Andrew Kozlik via bitcoin-dev wrote:

Quoted text (51 lines)
> Hi everyone,
>
> In the current draft of BIP-0341 [1] the signature message commits to the
> scriptPubKey of the output being spent by the input. I propose that the
> signature message should commit to the scriptPubKeys of *all* transaction
> inputs.
>
> In certain applications like CoinJoin, a wallet has to deal with
> transactions containing external inputs. To calculate the actual amount
> that the user is spending, the wallet needs to reliably determine for each
> input whether it belongs to the wallet or not. Without such a mechanism an
> adversary can fool the wallet into displaying incorrect information about
> the amount being spent, which can result in theft of user funds [2].
>
> In order to ascertain non-ownership of an input which is claimed to be
> external, the wallet needs the scriptPubKey of the previous output spent by
> this input. It must acquire the full transaction being spent and verify its
> hash against that which is given in the outpoint. This is an obstacle in
> the implementation of lightweight air-gapped wallets and hardware wallets
> in general. If the signature message would commit to the scriptPubKeys of
> all transaction inputs, then the wallet would only need to acquire the
> scriptPubKey of the output being spent without having to acquire and verify
> the hash of the entire previous transaction. If an attacker would provide
> an incorrect scriptPubKey, then that would cause the wallet to generate an
> invalid signature message.
>
> Note that committing only to the scriptPubKey of the output being spent is
> insufficient for this application, because the scriptPubKeys which are
> needed to ascertain non-ownership of external inputs are precisely the ones
> that would not be included in any of the signature messages produced by the
> wallet.
>
> The obvious way to implement this is to add another hash to the signature
> message:
> sha_scriptPubKeys (32): the SHA256 of the serialization of all
> scriptPubKeys of the previous outputs spent by this transaction.
>
> Cheers,
> Andrew Kozlik
>
> [1]
> https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
> [2]
> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html
>
>
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation•org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>
Pieter Wuille in reply to Jonas Nick permalink original

Hi all,

On Tuesday, May 5, 2020 3:20 AM, Jonas Nick via bitcoin-dev <bitcoin-dev@lists•linuxfoundation•org> wrote:

Quoted text (4 lines)
> This is a reasonable suggestion. Committing to every spent scriptPubKey and
> therefore every element of the TxOut instead of just the amount makes sense
> conceptually. And it would be a small diff (~4 lines + rationale) compared to
> the current bip-taproot version.

I agree.

There have been several steps so far towards making it possible for signers to determine whether they can safely sign with just O(1) information per input. This was initially attempted in BIP141 (by committing to spent input, to thwart the ability to lie about fees to ofline signers), and is improved in the current BIP341.

I think the CoinJoin + offline signer model indeed shows that is still incomplete, as it is yet another example where a signer may need to be provided with the entire creating transaction, which would be very unfortunate.

It's also counter to the model proposed by BIP147 (PSBT) workflows: the assumption is effectively already that it is sufficient to provide signers with just amount + scriptPubKey of the spent outputs. It feels very natural that signatures then indeed also need to commit to all that data; otherwise there should be ways that this information can be undetectably wrong.

AJ's approach seems great. It means not increasing the per-signature hashing, while retaining the ability to cache information across BIP141/BIP341.

As for coinbaseness and height: these are indeed also things currently kept track of in the UTXO set, but I don't think any signer is using this information to determine whether to sign or not (which I think is the minimum requirement for it to be included in a signature hash, see above). Signing height would cripple the ability to spend unconfirmed outputs, or force signers to reveal they're doing so (if done through a separate sighash flag) - both of which would be undesirable. That leaves coinbaseness, but I think the utility is very low.

The only downside is that this potentially slows down review, but I agree with earlier comments that it's hard to see how this would hurt. I also think it's important to get these things right from the start. Many things inside BIP341/BIP342 are extensible with future softforks, but signature hashes for key-path spends is not one of them (the set of potential signature hash semantics must be committed to directly by the output, so changing them requires a new output type - which would be highly unfortunate for fungibility reasons).

Thus, unless there are objections, I'd like to go through with this and make the suggested changes.

Thoughts?