Re: Safer sighashes and more granular SIGHASH_NOINPUT

Re: Safer sighashes and more granular SIGHASH_NOINPUT
2018-11-20 20:29 ` Anthony Towns
                   ` (4 more replies)
  
From: Pieter Wuille @ 2018-11-19 22:37 UTC (permalink / raw)
  To: Bitcoin Dev

Hello everyone,

For future segwit versions, I think it would be good add a few things
to the sighash by default that were overlooked in BIP143:
* Committing to the absolute transaction fee (in addition to just the
amount being spent in each input) would categorically remove concerns
about wallets lying about fees to HW devices or airgapped signers.
* Committing to the scriptPubKey (in addition to the scriptCode) would
prevent lying to devices about the type of output being spent, even
when the scriptCode is correct. As a reminder, the scriptCode is the
actually executed script (which is the redeemscript in non-segwit
P2SH, and the witnesscript in P2WSH/P2WPKH).

As this implies additional information that may not be desirable to
commit to in all circumstances, it makes sense to make these optional.
This obviously interacts with SIGHASH_NOINPUT, which really adds two
different ways of rebinding signatures to inputs:
* Changing the prevout (so that the txid doesn't need to be known when
the signature is created)
* Changing the script (so that the exact scriptPubKey/redeemScript/...
doesn't need to be known when the signature is created)

Of course, the second implies the first, but do all use cases require
both being able to change the prevout and (arbitrarily) changing the
scriptPubKey? While BIP118 correctly points out this is secure if the
same keys are only used in scripts with which binding is to be
permitted, I feel it would be preferable if signatures/scripts would
explicitly state what can change. One way to accomplish this is by
indicating exactly what in a script is subject to change.

Here is a combined proposal:
* Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
and SIGHASH_SCRIPTMASK.
* A new opcode OP_MASK is added, which acts as a NOP during execution.
* The sighash is computed like in BIP143, but:
  * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
the subsequent opcode/push is removed.
  * The scriptPubKey being spent is added to the sighash, unless
SIGHASH_SCRIPTMASK is set.
  * The transaction fee is added to the sighash, unless SIGHASH_NOFEE is set.
  * hashPrevouts, hashSequence, and outpoint are set to null when
SIGHASH_NOINPUT is set (like BIP118, but not for scriptCode).

So my question is whether anyone can see ways in which this introduces
redundant flexibility, or misses obvious use cases?

Cheers,

-- 
Pieter


 permalink raw reply	[|nested]
2018-11-19 22:37 Pieter Wuille

  2018-11-21 11:20   ` Christian Decker
  2018-11-21 17:55   ` Johnson Lau
  2018-11-21 11:15 ` Christian Decker
                   ` (3 subsequent siblings)
  
From: Anthony Towns @ 2018-11-20 20:29 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion

On Mon, Nov 19, 2018 at 02:37:57PM -0800, Pieter Wuille via bitcoin-dev wrote:
> Here is a combined proposal:
> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
> and SIGHASH_SCRIPTMASK.
> * A new opcode OP_MASK is added, which acts as a NOP during execution.
> * The sighash is computed like in BIP143, but:
>   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
> the subsequent opcode/push is removed.
>   * The scriptPubKey being spent is added to the sighash, unless
> SIGHASH_SCRIPTMASK is set.
>   * The transaction fee is added to the sighash, unless SIGHASH_NOFEE is set.
>   * hashPrevouts, hashSequence, and outpoint are set to null when
> SIGHASH_NOINPUT is set (like BIP118, but not for scriptCode).

Current flags are {ALL, NONE, SINGLE} and ANYONECANPAY, and the BIP143
tx digest consists of the hash of:

  1 nVersion
  4 outpoint
  5 input scriptCode
  6 input's outpoint value
  7 input's nSeq
  9 nLocktime
 10 sighash

  2 hashPrevOuts (commits to 4,5,6; unless ANYONECANPAY)
  3 hashSequence (commits to 7; only if ALL and not ANYONECANPAY)
  8 hashOutputs
       - NONE: 0
       - SINGLE: {value,scriptPubKey} for corresponding output
       - otherwise: {value,scriptPubKey} for all outputs

The fee is committed to by hashPrevOuts and hashOutputs, which means
NOFEE is only potentially useful if ANYONECANPAY or NONE or SINGLE is set.

For NOINPUT, (2),(3),(4) are cleared, and SCRIPTMASK (which munges (5))
is only useful given NOINPUT, since (4) indirectly commits to (5). 

Given this implementation, NOINPUT effectively implies ANYONECANPAY,
I think. (I think that is also true of BIP 118's NOINPUT spec)

Does it make sense to treat this as two classes of options, affecting
the input and output side:

  output: (pick one, using bits 0,1)
    * NONE -- don't care where the money goes
    * SINGLE -- want this output
    * ALL -- want exactly this set of outputs

  input: (pick one, using bits 4,5)
    * PARTIALSCRIPT -- spending from some tx with roughly this script (and
                       maybe others; SCRIPTMASK|NOINPUT|ANYONECANPAY)
    * KNOWNSCRIPT -- spending from some tx with exactly this script (and
                     maybe others; NOINPUT|ANYONECANPAY)
    * KNOWNTX -- spending from this tx (and maybe others; ANYONECANPAY)
    * ALL_INPUTS -- spending from exactly these txes

  combo: (flag, bit 6)
    * NOFEE -- don't commit to the fee

I think NONE without NOFEE doesn't make much sense, and
NOFEE|ALL|ALL_INPUTS would also be pretty weird. Might make sense to
warn/error on signing when asking for those combinations, and maybe even
to fail on validating them.

(Does it make sense to keep SIGHASH_NONE? I guess SIGHASH_NONE|ALL_INPUTS
could be useful if you just use sigs on one of the other inputs to commit
to a useful output)

FWIW, OP_MASK seems a bit complicated to me. How would you mask a script
that looks like:

   OP_MASK IF <p> ENDIF <q> ...

or:

   IF OP_MASK ENDIF <p> ...

I guess if you make the rule be "for every OP_MASK in scriptCode the
*immediately* subsequent opcode/push is removed (if present)" it would
be fine though -- that would make OP_MASK in both the above not have
any effect. (Maybe a more explicit name like "MASK_PUSH_FOR_SIGHASH"
or something might be good?)

I don't have a reason why, but committing to the scriptCode feels to me
like it reduces the "hackiness" of NOINPUT a lot.

Cheers,
aj



 permalink raw reply	[|nested]
2018-11-19 22:37 Pieter Wuille
  2018-11-20 20:29 ` Anthony Towns

  2018-11-23  6:04   ` Anthony Towns
  2018-11-21 17:07 ` Russell O'Connor
                   ` (2 subsequent siblings)
  
From: Christian Decker @ 2018-11-21 11:15 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion, Bitcoin Dev

Hi Pieter,

great proposal, I think this may address some of the (perceived)
downsides of BIP118, by committing to the script when possible
(always?). One minor thing that I noticed a while ago and that I meant
to fix on BIP118 is that `hashSequence` does not need to be blanked for
eltoo to work (since where it is needed we also use `sighash_single`),
so I'm tempted to remove that redundant blanking. It may not make a lot
of difference but it'd limit the ability to change the number of inputs
to a NOINPUT transaction (this now being the only field that commits to
the set of inputs).

As for your proposal, I really like the `sighash_scriptmask` proposal,
and committing to the fees (with the `nofee` escape hatch) also works
seems also a nice fix. My one concern is that introducing a new opcode
to mask things in the sighash looks like a similar layering violation as
`codeseparator` was, but that's just a minor issue imho.

Cheers,
Christian

Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org>
writes:
> Hello everyone,
>
> For future segwit versions, I think it would be good add a few things
> to the sighash by default that were overlooked in BIP143:
> * Committing to the absolute transaction fee (in addition to just the
> amount being spent in each input) would categorically remove concerns
> about wallets lying about fees to HW devices or airgapped signers.
> * Committing to the scriptPubKey (in addition to the scriptCode) would
> prevent lying to devices about the type of output being spent, even
> when the scriptCode is correct. As a reminder, the scriptCode is the
> actually executed script (which is the redeemscript in non-segwit
> P2SH, and the witnesscript in P2WSH/P2WPKH).
>
> As this implies additional information that may not be desirable to
> commit to in all circumstances, it makes sense to make these optional.
> This obviously interacts with SIGHASH_NOINPUT, which really adds two
> different ways of rebinding signatures to inputs:
> * Changing the prevout (so that the txid doesn't need to be known when
> the signature is created)
> * Changing the script (so that the exact scriptPubKey/redeemScript/...
> doesn't need to be known when the signature is created)
>
> Of course, the second implies the first, but do all use cases require
> both being able to change the prevout and (arbitrarily) changing the
> scriptPubKey? While BIP118 correctly points out this is secure if the
> same keys are only used in scripts with which binding is to be
> permitted, I feel it would be preferable if signatures/scripts would
> explicitly state what can change. One way to accomplish this is by
> indicating exactly what in a script is subject to change.
>
> Here is a combined proposal:
> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
> and SIGHASH_SCRIPTMASK.
> * A new opcode OP_MASK is added, which acts as a NOP during execution.
> * The sighash is computed like in BIP143, but:
>   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
> the subsequent opcode/push is removed.
>   * The scriptPubKey being spent is added to the sighash, unless
> SIGHASH_SCRIPTMASK is set.
>   * The transaction fee is added to the sighash, unless SIGHASH_NOFEE is set.
>   * hashPrevouts, hashSequence, and outpoint are set to null when
> SIGHASH_NOINPUT is set (like BIP118, but not for scriptCode).
>
> So my question is whether anyone can see ways in which this introduces
> redundant flexibility, or misses obvious use cases?
>
> Cheers,
>
> -- 
> Pieter
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev


 permalink raw reply	[|nested]
2018-11-20 20:29 ` Anthony Towns

  2018-11-21 17:55   ` Johnson Lau
  
From: Christian Decker @ 2018-11-21 11:20 UTC (permalink / raw)
  To: Anthony Towns, Bitcoin Protocol Discussion, Pieter Wuille,
	Bitcoin Protocol Discussion

Anthony Towns via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org>
writes:
> Given this implementation, NOINPUT effectively implies ANYONECANPAY,
> I think. (I think that is also true of BIP 118's NOINPUT spec)

I mentioned this in my reply to Pieter, but this may not be true if we
remove the blanking of the `hashSequence` field. Anyonecanpay would
allow changing the number of inputs in an arbitrary fashion, while
`noinput` without the blanking would (in a weird roundabout way) still
commit to the number of inputs. Maybe we want to make that more explicit
by also hashing the number of inputs? But I can't think of a good
usecase for keeping that, with noinput.

Cheers,
Christian


 permalink raw reply	[|nested]
* 
  2018-11-19 22:37 Pieter Wuille
                   ` 
  2018-11-21 17:07 ` 

  2018-11-28  8:31   ` Johnson Lau
                     ` (2 more replies)
  2018-12-12  9:42 ` Rusty Russell
  4 siblings, 3 replies; 55+ messages in thread
From: Pieter Wuille @ 2018-11-28  3:41 UTC (permalink / raw)
  To: Bitcoin Dev

On Mon, 19 Nov 2018 at 14:37, Pieter Wuille <pieter.wuille@gmail•com> wrote:
> Here is a combined proposal:
> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE, and SIGHASH_SCRIPTMASK.
> * A new opcode OP_MASK is added, which acts as a NOP during execution.
> * The sighash is computed like in BIP143, but:
>   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode the subsequent opcode/push is removed.
>   * The scriptPubKey being spent is added to the sighash, unless SIGHASH_SCRIPTMASK is set.
>   * The transaction fee is added to the sighash, unless SIGHASH_NOFEE is set.
>   * hashPrevouts, hashSequence, and outpoint are set to null when SIGHASH_NOINPUT is set (like BIP118, but not for scriptCode).

Thanks for all the input so far. Going over the suggestions and other ideas:

* OP_MASK should be required to be followed by a push, as suggested by
Anthony Towns. The alternative would permit substituting arbitrary
opcodes for masked pushes, which is at least very hard to reason
about. This would effectively turn it into a multi-byte OP_MASKEDPUSH
opcode.

* It's probably better to sign the amounts of all inputs, as suggested
by Johnson Lau. As that would cause default sighashes to sign all
input and output amounts, is there still a need to sign the tx fee
explicitly? Or in other words, are there situations where changing the
set of inputs or outputs after signing is desired, but the net
difference between them cannot change? If not, that would remove the
need for NOFEE.

* Do we need to keep the rule that sequence values of other inputs are
only signed with default sighash? It feels cleaner to always sign the
sequence values of all inputs that are included in the sighash anyway
(so all of them, unless ANYONECANPAY or NOINPUT, which would make it
sign only the current input's sequence value). If NOINPUT also blanks
the sequence values (as currently specified by BIP118), and all input
amounts are signed, that would make amounts/sequence values always be
treated identically.

* If MASK implies NOINPUT, and NOINPUT implies ANYONECANPAY, the 3 of
them can be encoded in just 2 bits using the
PARTIALSCRIPT/KNOWNSCRIPT/KNOWNTX/ALL_INPUTS encoding Anthony Towns
suggested.

* Regarding the discussion about preventing signatures from being
rebound to a different script(path)/checksig:
  * With MAST there is indeed less need for this, but at least
single-tree MAST constructions cannot replace all script branches (a
script with 40 IF/THEN/ELSE constructions may have 2^40 different
execution paths, for which computing a Merkle tree is intractable).
  * Just signing the opcode position of the CHECKSIG operator isn't
enough for all cases either. For example, you could have a complex
nested set of branches that puts a number of pubkeys on the stack, and
then a CHECKMULTISIG after the last ENDIF to verify all of them. In
such a situation, if the same key can occur in multiple combinations,
you still may want to prevent a signature generated for one
combination from being rebindable to the same key in another
combination. I believe that signing the opcode position plus the
true/false condition of all previous(?) IF statements is probably
sufficient to achieve that, but it would also introduce unnecessary
complexity for signers in most cases (see next point).
  * Thinking about signing code, adding these sort of execution trace
commitments to the sighash means they need to know which checksig
operator etc. they are signing for. I believe that in practice for
example HW devices will just whatever position the wallet indicated,
rather than verifying it corresponds with a particular intended code
path. Preventing rebinding isn't very useful if an attacker can make
you bind to the wrong thing regardless, so I'm not convinced this is
even worth having by default.
  * An alternative (not sure who suggested it) is to simply make every
CHECKSIG sign the opcode position of the last executed CODESEPARATOR
(and remove the earlier cut-of-scriptCode effect of CODESEPARATOR).
This gives a simple (but somewhat limited) way for scripts that need
to prevent certain kinds of cross-execution-trace rebinding.

A few misc ideas:
* (Taken from https://github.com/jl2012/bips/blob/sighash2/bip-sighash2.mediawiki)
For a default sign-everything sighash, the sighash byte can be
dropped.
* For the commitments to the scriptPubKey and scriptCode, an
intermediary hash should be used (so the data included in the sighash
includes a hash of those, rather than the script directly). This
prevents a blow up in hashing time for large scripts with many
different sighash types in its signatures.
* When masking the scriptCode, the push opcode immediately following
OP_MASKEDPUSH can be replaced by OP_VERIF (which will never collide
with any real script, as OP_VERIF makes a script invalid even when
occurring in an unexecuted branch).
* Sighashes (and really all new hashes that are introduced) should be
prefixed with a fixed 64-byte array as "tag", chosen to not collide
with any existing use of SHA256 in Bitcoin, to prevent signatures from
being re-interpretable as something else. Picking 64 bytes as tag size
means it can be efficiently implemented as just a modified SHA256 IV.

So a combined proposal:
* All existing sighash flags, plus NOINPUT and MASK
(ANYONECANPAY/NOINPUT/MASK are encoded in 2 bits).
* A new opcode called OP_MASKEDPUSH, whose only runtime behaviour is
failing if not immediately followed by a push, or when appearing as
last opcode in the script.
* Signatures are 64 plus an optional sighash byte. A missing sighash
byte implies ALL, and ALL cannot be specified explicitly.
* The sighash is computed from the following:
  * A 64-byte constant tag
  * Data about the spending transaction:
    * The transaction version number
    * The hash of txins' prevouts+amounts+sequences (or nothing if ANYONECANPAY)
    * The hash of all txouts (or just the corresponding txout if
SINGLE; nothing if NONE)
    * The transaction locktime
  * Data about the output being spent:
    * The prevout (or nothing if NOINPUT)
    * The amount
    * The sequence number
    * The hash of the scriptPubKey (or nothing if MASK)
  * Data about the script being executed:
    * The hash of the scriptCode (after masking out, if MASK is set)
    * The opcode number of the last executed OP_CODESEPARATOR (or
0xFFFFFFFF if none)
  * The sighash mode

Cheers,

-- 
Pieter


^ permalink raw reply	[|nested] 55+ messages in thread
2018-11-20 20:29 ` Anthony Towns
  2018-11-21 11:20   ` Christian Decker

  
From: Johnson Lau @ 2018-11-21 17:55 UTC (permalink / raw)
  To: Anthony Towns, bitcoin-dev

If we sign the txids of all inputs, we should also explicitly commit to their values. Only this could fully eliminate any possible way to lie about input value to hardware wallets

> Does it make sense to keep SIGHASH_NONE?
SIGHASH_NONE should be kept. ANYONECANPAY|NONE allows donation of dust UTXOs to miners

> I think NONE without NOFEE doesn't make much sense…….
We might refuse to sign weird combinations like NOFEE|ALLINPUT|ALLOUTPUT. But to keep the consensus logic simple, we should just validate it as usual.

> OP_MASK seems a bit complicated to me. …...
Yes, it looks complicated to me, and it improves security only in some avoidable edge cases in SIGHASH_NOINPUT:

The common case: the exact masked script or address is reused. OP_MASK can’t prevent signature replay since the masked script is the same.

The avoidable case: the same public key is reused in different script templates. OP_MASK may prevent signature replay is the masked script is not the same.

The latter case is totally avoidable since one could and should use a different public key for different script.

It could be made much simpler as NOINPUT with/without SCRIPT. This again is only helpful in the avoidable case above, but it doesn’t bring too much complexity.

> I don't have a reason why, but committing to the scriptCode feels to me like it reduces the "hackiness" of NOINPUT a lot.
OP_MASK is designed to preserve the hackiness, while provide some sort of replay protection (only in avoidable cases). However, I’m not sure who would actually need NOINPUT with KNOWNSCRIPT

> On 21 Nov 2018, at 4:29 AM, Anthony Towns via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> On Mon, Nov 19, 2018 at 02:37:57PM -0800, Pieter Wuille via bitcoin-dev wrote:
>> Here is a combined proposal:
>> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
>> and SIGHASH_SCRIPTMASK.
>> * A new opcode OP_MASK is added, which acts as a NOP during execution.
>> * The sighash is computed like in BIP143, but:
>>  * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
>> the subsequent opcode/push is removed.
>>  * The scriptPubKey being spent is added to the sighash, unless
>> SIGHASH_SCRIPTMASK is set.
>>  * The transaction fee is added to the sighash, unless SIGHASH_NOFEE is set.
>>  * hashPrevouts, hashSequence, and outpoint are set to null when
>> SIGHASH_NOINPUT is set (like BIP118, but not for scriptCode).
> 
> Current flags are {ALL, NONE, SINGLE} and ANYONECANPAY, and the BIP143
> tx digest consists of the hash of:
> 
>  1 nVersion
>  4 outpoint
>  5 input scriptCode
>  6 input's outpoint value
>  7 input's nSeq
>  9 nLocktime
> 10 sighash
> 
>  2 hashPrevOuts (commits to 4,5,6; unless ANYONECANPAY)
>  3 hashSequence (commits to 7; only if ALL and not ANYONECANPAY)
>  8 hashOutputs
>       - NONE: 0
>       - SINGLE: {value,scriptPubKey} for corresponding output
>       - otherwise: {value,scriptPubKey} for all outputs
> 
> The fee is committed to by hashPrevOuts and hashOutputs, which means
> NOFEE is only potentially useful if ANYONECANPAY or NONE or SINGLE is set.
> 
> For NOINPUT, (2),(3),(4) are cleared, and SCRIPTMASK (which munges (5))
> is only useful given NOINPUT, since (4) indirectly commits to (5). 
> 
> Given this implementation, NOINPUT effectively implies ANYONECANPAY,
> I think. (I think that is also true of BIP 118's NOINPUT spec)
> 
> Does it make sense to treat this as two classes of options, affecting
> the input and output side:
> 
>  output: (pick one, using bits 0,1)
>    * NONE -- don't care where the money goes
>    * SINGLE -- want this output
>    * ALL -- want exactly this set of outputs
> 
>  input: (pick one, using bits 4,5)
>    * PARTIALSCRIPT -- spending from some tx with roughly this script (and
>                       maybe others; SCRIPTMASK|NOINPUT|ANYONECANPAY)
>    * KNOWNSCRIPT -- spending from some tx with exactly this script (and
>                     maybe others; NOINPUT|ANYONECANPAY)
>    * KNOWNTX -- spending from this tx (and maybe others; ANYONECANPAY)
>    * ALL_INPUTS -- spending from exactly these txes
> 
>  combo: (flag, bit 6)
>    * NOFEE -- don't commit to the fee
> 
> I think NONE without NOFEE doesn't make much sense, and
> NOFEE|ALL|ALL_INPUTS would also be pretty weird. Might make sense to
> warn/error on signing when asking for those combinations, and maybe even
> to fail on validating them.
> 
> (Does it make sense to keep SIGHASH_NONE? I guess SIGHASH_NONE|ALL_INPUTS
> could be useful if you just use sigs on one of the other inputs to commit
> to a useful output)
> 
> FWIW, OP_MASK seems a bit complicated to me. How would you mask a script
> that looks like:
> 
>   OP_MASK IF <p> ENDIF <q> ...
> 
> or:
> 
>   IF OP_MASK ENDIF <p> ...
> 
> I guess if you make the rule be "for every OP_MASK in scriptCode the
> *immediately* subsequent opcode/push is removed (if present)" it would
> be fine though -- that would make OP_MASK in both the above not have
> any effect. (Maybe a more explicit name like "MASK_PUSH_FOR_SIGHASH"
> or something might be good?)
> 
> I don't have a reason why, but committing to the scriptCode feels to me
> like it reduces the "hackiness" of NOINPUT a lot.
> 
> Cheers,
> aj
> 
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev




 permalink raw reply	[|nested]
2018-11-21 17:07 ` Russell O'Connor

  2018-11-22 16:23     ` Russell O'Connor
  2018-11-23  5:03   ` Anthony Towns
  
From: Johnson Lau @ 2018-11-22 14:28 UTC (permalink / raw)
  To: Russell O'Connor, bitcoin-dev

[-- Attachment #1: Type: text/plain, Size: 2849 bytes --]

With MAST in taproot, OP_IF etc become mostly redundant, with worse privacy. To maximise fungibility, we should encourage people to use MAST, instead of improve the functionality of OP_IF and further complicate the protocol.


> On 22 Nov 2018, at 1:07 AM, Russell O'Connor via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> On Mon, Nov 19, 2018 at 10:22 PM Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org <mailto:bitcoin-dev@lists•linuxfoundation.org>> wrote:
> So my question is whether anyone can see ways in which this introduces
> redundant flexibility, or misses obvious use cases?
> 
> Hopefully my comment is on-topic for this thread:
> 
> Given that we want to move away from OP_CODESEPARATOR, because each call to this operation effectively takes O(script-size) time, we need a replacement for the functionality it currently provides.  While perhaps the original motivation for OP_CODESEPARTOR is surrounded in mystery, it currently can be used (or perhaps abused) for the task of creating signature that covers, not only which input is being signed, but which specific branch within that input Script code is being signed for.
> 
> For example, one can place an OP_CODESEPARATOR within each branch of an IF block, or by placing an OP_CODESEPARATOR before each OP_CHECKSIG operation.  By doing so, signatures created for one clause cannot be used as signatures for another clause.  Since different clauses in Bitcoin Script may be enforcing different conditions (such as different time-locks, hash-locks, etc), it is useful to be able to sign in such a way that your signature is only valid when the conditions for a particular branch are satisfied.  In complex Scripts, it may not be practical or possible to use different public keys for every different clause. (In practice, you will be able to get away with fewer OP_CODESEPARATORS than one in every IF block).
> 
> One suggestion I heard (I think I heard it from Pieter) to achieve the above is to add an internal counter that increments on every control flow operator, OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, and have the signature cover the value of this counter.  Equivalently we divide every Bitcoin Script program into blocks deliminated by these control flow operator and have the signature cover the index of the block that the OP_CHECKSIG occurs within.  More specifically, we will want a SigHash flag to enables/disable the signature covering this counter.
> 
> There are many different ways one might go about replacing the remaining useful behaviour of OP_CODESEPARATOR than the one I gave above. I would be happy with any solution.
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev


[-- Attachment #2: Type: text/html, Size: 3989 bytes --]

 permalink raw reply	[|nested]
2018-11-22 14:28   ` Johnson Lau

  2018-11-22 20:52       ` Johnson Lau
  
From: Russell O'Connor @ 2018-11-22 16:23 UTC (permalink / raw)
  To: Johnson Lau;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 3384 bytes --]

I see, so your suggestion is that a sequence of OP_IF ... OP_ENDIF can be
replaced by a Merklized Script tree of that depth in practice.

I'm concerned that at script creation time it takes exponential time to
complete a Merkle root of depth 'n'.  Can anyone provide benchmarks or
estimates of how long it takes to compute a Merkle root of a full tree of
various depths on typical consumer hardware?  I would guess things stop
becoming practical at a depth of 20-30.

On Thu, Nov 22, 2018 at 9:28 AM Johnson Lau <jl2012@xbt•hk> wrote:

> With MAST in taproot, OP_IF etc become mostly redundant, with worse
> privacy. To maximise fungibility, we should encourage people to use MAST,
> instead of improve the functionality of OP_IF and further complicate the
> protocol.
>
>
> On 22 Nov 2018, at 1:07 AM, Russell O'Connor via bitcoin-dev <
> bitcoin-dev@lists•linuxfoundation.org> wrote:
>
> On Mon, Nov 19, 2018 at 10:22 PM Pieter Wuille via bitcoin-dev <
> bitcoin-dev@lists•linuxfoundation.org> wrote:
>
>> So my question is whether anyone can see ways in which this introduces
>> redundant flexibility, or misses obvious use cases?
>>
>
> Hopefully my comment is on-topic for this thread:
>
> Given that we want to move away from OP_CODESEPARATOR, because each call
> to this operation effectively takes O(script-size) time, we need a
> replacement for the functionality it currently provides.  While perhaps the
> original motivation for OP_CODESEPARTOR is surrounded in mystery, it
> currently can be used (or perhaps abused) for the task of creating
> signature that covers, not only which input is being signed, but which
> specific branch within that input Script code is being signed for.
>
> For example, one can place an OP_CODESEPARATOR within each branch of an IF
> block, or by placing an OP_CODESEPARATOR before each OP_CHECKSIG
> operation.  By doing so, signatures created for one clause cannot be used
> as signatures for another clause.  Since different clauses in Bitcoin
> Script may be enforcing different conditions (such as different time-locks,
> hash-locks, etc), it is useful to be able to sign in such a way that your
> signature is only valid when the conditions for a particular branch are
> satisfied.  In complex Scripts, it may not be practical or possible to use
> different public keys for every different clause. (In practice, you will be
> able to get away with fewer OP_CODESEPARATORS than one in every IF block).
>
> One suggestion I heard (I think I heard it from Pieter) to achieve the
> above is to add an internal counter that increments on every control flow
> operator, OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, and have the signature cover
> the value of this counter.  Equivalently we divide every Bitcoin Script
> program into blocks deliminated by these control flow operator and have the
> signature cover the index of the block that the OP_CHECKSIG occurs within.
> More specifically, we will want a SigHash flag to enables/disable the
> signature covering this counter.
>
> There are many different ways one might go about replacing the remaining
> useful behaviour of OP_CODESEPARATOR than the one I gave above. I would be
> happy with any solution.
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>
>
>

[-- Attachment #2: Type: text/html, Size: 4492 bytes --]

 permalink raw reply	[|nested]
2018-11-22 16:23     ` Russell O'Connor

  2018-11-22 22:10         ` Russell O'Connor
  
From: Johnson Lau @ 2018-11-22 20:52 UTC (permalink / raw)
  To: Russell O'Connor;  bitcoin-dev

Assuming a script size of 128 bytes (including SHA256 padding), 2^20 scripts is 134MB. Double it to 268MB for the merkle branch hashes. With roughly 100MB/s, this should take 2.5s (or 42min for 30 levels). However, memory use is not considered.

>each call to this operation effectively takes O(script-size) time
I’m not sure if this is correct. Actually, CTransactionSignatureSerializer() scans every script for OP_CODESEPARATOR. Scripts with and without OP_CODESEPARATOR should take exactly the same O(script-size) time (see https://github.com/bitcoin/bitcoin/pull/14786)
Also, this is no longer a concern under segwit (BIP143), which CTransactionSignatureSerializer() is not used. Actually, OP_CODESEPARATOR under segwit is way simpler than the proposed OP_MASK. If one finds OP_MASK acceptable, there should be no reason to reject OP_CODESEPARATOR.

>One suggestion I heard (I think I heard it from Pieter) to achieve the above is to add an internal counter that increments on every control flow operator,……...
If I have to choose among OP_CODESEPARATOR and “flow operator counting”, I’d rather choose OP_CODESEPARATOR. At least we don’t need to add more lines to the consensus code, just for something that is mostly archivable with MAST.


> On 23 Nov 2018, at 12:23 AM, Russell O'Connor <roconnor@blockstream•io> wrote:
> 
> I see, so your suggestion is that a sequence of OP_IF ... OP_ENDIF can be replaced by a Merklized Script tree of that depth in practice.
> 
> I'm concerned that at script creation time it takes exponential time to complete a Merkle root of depth 'n'.  Can anyone provide benchmarks or estimates of how long it takes to compute a Merkle root of a full tree of various depths on typical consumer hardware?  I would guess things stop becoming practical at a depth of 20-30.
> 
> On Thu, Nov 22, 2018 at 9:28 AM Johnson Lau <jl2012@xbt•hk> wrote:
> With MAST in taproot, OP_IF etc become mostly redundant, with worse privacy. To maximise fungibility, we should encourage people to use MAST, instead of improve the functionality of OP_IF and further complicate the protocol.
> 
> 
>> On 22 Nov 2018, at 1:07 AM, Russell O'Connor via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
>> 
>> On Mon, Nov 19, 2018 at 10:22 PM Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
>> So my question is whether anyone can see ways in which this introduces
>> redundant flexibility, or misses obvious use cases?
>> 
>> Hopefully my comment is on-topic for this thread:
>> 
>> Given that we want to move away from OP_CODESEPARATOR, because each call to this operation effectively takes O(script-size) time, we need a replacement for the functionality it currently provides.  While perhaps the original motivation for OP_CODESEPARTOR is surrounded in mystery, it currently can be used (or perhaps abused) for the task of creating signature that covers, not only which input is being signed, but which specific branch within that input Script code is being signed for.
>> 
>> For example, one can place an OP_CODESEPARATOR within each branch of an IF block, or by placing an OP_CODESEPARATOR before each OP_CHECKSIG operation.  By doing so, signatures created for one clause cannot be used as signatures for another clause.  Since different clauses in Bitcoin Script may be enforcing different conditions (such as different time-locks, hash-locks, etc), it is useful to be able to sign in such a way that your signature is only valid when the conditions for a particular branch are satisfied.  In complex Scripts, it may not be practical or possible to use different public keys for every different clause. (In practice, you will be able to get away with fewer OP_CODESEPARATORS than one in every IF block).
>> 
>> One suggestion I heard (I think I heard it from Pieter) to achieve the above is to add an internal counter that increments on every control flow operator, OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, and have the signature cover the value of this counter.  Equivalently we divide every Bitcoin Script program into blocks deliminated by these control flow operator and have the signature cover the index of the block that the OP_CHECKSIG occurs within.  More specifically, we will want a SigHash flag to enables/disable the signature covering this counter.
>> 
>> There are many different ways one might go about replacing the remaining useful behaviour of OP_CODESEPARATOR than the one I gave above. I would be happy with any solution.
>> _______________________________________________
>> bitcoin-dev mailing list
>> bitcoin-dev@lists•linuxfoundation.org
>> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
> 




 permalink raw reply	[|nested]
2018-11-22 20:52       ` Johnson Lau

  2018-11-23 10:47           ` Johnson Lau
  
From: Russell O'Connor @ 2018-11-22 22:10 UTC (permalink / raw)
  To: Johnson Lau;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 2163 bytes --]

On Thu, Nov 22, 2018 at 3:53 PM Johnson Lau <jl2012@xbt•hk> wrote:

> Assuming a script size of 128 bytes (including SHA256 padding), 2^20
> scripts is 134MB. Double it to 268MB for the merkle branch hashes. With
> roughly 100MB/s, this should take 2.5s (or 42min for 30 levels). However,
> memory use is not considered.
>
> >each call to this operation effectively takes O(script-size) time
> I’m not sure if this is correct. Actually,
> CTransactionSignatureSerializer() scans every script for OP_CODESEPARATOR.
> Scripts with and without OP_CODESEPARATOR should take exactly the same
> O(script-size) time (see https://github.com/bitcoin/bitcoin/pull/14786)
> Also, this is no longer a concern under segwit (BIP143), which
> CTransactionSignatureSerializer() is not used. Actually, OP_CODESEPARATOR
> under segwit is way simpler than the proposed OP_MASK. If one finds OP_MASK
> acceptable, there should be no reason to reject OP_CODESEPARATOR.
>

Even still, each call to OP_CODESEPARATOR / OP_CHECKSIG pair requires
recomputing a new #5. scriptCode from BIP 143, and hence computes a new
transaction digest.  I understood that this issue was the main motivation
for wanting to deprecate OP_CODESEPARATOR and remove it from later versions
of script.

However, given that we are looking at a combinatorial explosion in SIGHASH
flag combinations already, coupled with existing SigOp limitations, maybe
the cost of recomputing scriptCode with OP_CODESEPARATOR isn't such a big
deal.

And even if we choose remove the behavior of OP_CODESEPARATOR in new
versions of Script, it seems more than 30 layers of sequential OP_IFs can
be MASTified, so there is no need to use OP_CODESEPARATOR within that limit.

>One suggestion I heard (I think I heard it from Pieter) to achieve the
above is to add an internal counter that increments on every control flow
operator,……...

> If I have to choose among OP_CODESEPARATOR and “flow operator counting”,
> I’d rather choose OP_CODESEPARATOR. At least we don’t need to add more
> lines to the consensus code, just for something that is mostly archivable
> with MAST.
>

[-- Attachment #2: Type: text/html, Size: 2721 bytes --]

 permalink raw reply	[|nested]
2018-11-21 17:07 ` Russell O'Connor
  2018-11-22 14:28   ` Johnson Lau

  2018-11-23 20:18     ` Russell O'Connor
  
From: Anthony Towns @ 2018-11-23  5:03 UTC (permalink / raw)
  To: Russell O'Connor, Bitcoin Protocol Discussion

On Wed, Nov 21, 2018 at 12:07:30PM -0500, Russell O'Connor via bitcoin-dev wrote:
> Given that we want to move away from OP_CODESEPARATOR, because each call to
> this operation effectively takes O(script-size) time, we need a replacement for
> the functionality it currently provides.  While perhaps the original motivation
> for OP_CODESEPARTOR is surrounded in mystery, it currently can be used (or
> perhaps abused) for the task of creating signature that covers, not only which
> input is being signed, but which specific branch within that input Script code
> is being signed for.

Would it be sufficient to sign the position within the script of the
last OP_CODESEPARATOR? That is, if your script is:

   DUP DUP CHECKSIG CODESEP CHECKSIG CODESEP CHECKSIG

with the idea being that it can be spent by providing any pub key and
three different signatures by that key, with the first sig committing
to a "codesep position" of 0, the second a "codesep position" of 4,
and the third a "codesep position" of 6? In each case, the signature
also commits to the full (possibly masked) script as well.

I think that covers all the behaviour you can currently achieve with
CODESEP (which is pretty limited since every sig effectively commits
to the full redeem script, and you can't commit to subsets of the
signature/witness), and it keeps the things you can do with the various
features a bit orthogonal:

 NOINPUT -- lets the sig apply to different transactions
 OP_MASK -- lets the different txes have variations in the script the
            sig applies to
 CODESEP -- lets you require different sigs for different parts of a
            single script
 MAST[0] -- provides alternative scripts, doesn't affect sigs
 IF/etc  -- provides control flow within a script, doesn't affect sigs

Cheers,
aj

[0] (I think I'm going to claim "MAST" stands for "merkelized alternative
     script tree" these days, since they're not "abstract syntax trees")



 permalink raw reply	[|nested]
2018-11-21 11:15 ` Christian Decker

  2018-11-23  9:40     ` Christian Decker
  
From: Anthony Towns @ 2018-11-23  6:04 UTC (permalink / raw)
  To: Christian Decker, Bitcoin Protocol Discussion

On Wed, Nov 21, 2018 at 12:15:44PM +0100, Christian Decker via bitcoin-dev wrote:
> One minor thing that I noticed a while ago and that I meant
> to fix on BIP118 is that `hashSequence` does not need to be blanked for
> eltoo to work (since where it is needed we also use `sighash_single`),
> so I'm tempted to remove that redundant blanking. It may not make a lot
> of difference but it'd limit the ability to change the number of inputs
> to a NOINPUT transaction (this now being the only field that commits to
> the set of inputs).

Commiting to just the sequence numbers seems really weird to me; it
only really prevents you from adding inputs, since you could still
replace any input that was meant to be there by almost any arbitrary
other transaction...

I could see this *maybe* making sense if you at least committed to the
values of each input's outpoint; since that would be an actual constraint?

I don't think you can commit to anything else about the other inputs:

   -- txids of the other transactions wouldn't work if you had other
      NOINPUT txes, and would introduce O(N^2) validation cost if someone
      signed every input with NOINPUT but committed to the txids of
      every other input

   -- scriptPubKeys wouldn't really work for eltoo-like constructions
      that want to vary the scripts but apply the same sig, but might
      work sometimes?

   -- witness scripts for the other inputs could be unknown at your
      signing time, or arbitrarily large and thus a pain to have to send
      to a hardware wallet

Just treating NOINPUT as a subset of ANYONECANPAY seems simpler to
me though...

> As for your proposal, I really like the `sighash_scriptmask` proposal,
> and committing to the fees (with the `nofee` escape hatch) also works
> seems also a nice fix. My one concern is that introducing a new opcode
> to mask things in the sighash looks like a similar layering violation as
> `codeseparator` was, but that's just a minor issue imho.

I think OP_MASK is okay as far as layering goes, if you just think of it
as a (set of) multibyte "OP_MASKED_PUSH" opcode(s). So when you
pseudocode a script like:

    <n> OP_CSV OP_DROP <p> OP_CHECKSIG

and then decide <n> needs to be masked, you rewrite it as:

    [n] OP_CSV OP_DROP <p> OP_CHECKSIG

indicating n is masked, and don't worry about the exact bytes that will
encode the push, anymore than you currently worry about whether it's
OP_0, OP_1..16, <1..75>+1..75-bytes, PUSHDATA[1,2,3]+n+n-bytes.

As long as OP_MASK only applies to a PUSH and it's an error for OP_MASK
not to be immediately followed by that PUSH, I think that all works
out fine.

Cheers,
aj



 permalink raw reply	[|nested]
2018-11-23  6:04   ` Anthony Towns

  2018-11-24  8:13       ` Johnson Lau
  
From: Christian Decker @ 2018-11-23  9:40 UTC (permalink / raw)
  To: Anthony Towns, Bitcoin Protocol Discussion

Anthony Towns <aj@erisian•com.au> writes:
> Commiting to just the sequence numbers seems really weird to me; it
> only really prevents you from adding inputs, since you could still
> replace any input that was meant to be there by almost any arbitrary
> other transaction...

It's a really roundabout way of committing to the inputs, I
agree. I'm actually wondering if it makes sense to correct that
additional blanked field in BIP118 at all since it seems there is no
real use-case for NOINPUT that doesn't involve blanking the
`hashSequence` as well.

> I could see this *maybe* making sense if you at least committed to the
> values of each input's outpoint; since that would be an actual constraint?

BIP118 still commits to the value of the input being spent, i.e.,
6. value is not being blanked in the current proposal. This is on
purpose since we commit to the outputs, not committing to the input
values could end up with unexpected fees.

>> As for your proposal, I really like the `sighash_scriptmask` proposal,
>> and committing to the fees (with the `nofee` escape hatch) also works
>> seems also a nice fix. My one concern is that introducing a new opcode
>> to mask things in the sighash looks like a similar layering violation as
>> `codeseparator` was, but that's just a minor issue imho.
>
> I think OP_MASK is okay as far as layering goes, if you just think of it
> as a (set of) multibyte "OP_MASKED_PUSH" opcode(s). So when you
> pseudocode a script like:
>
>     <n> OP_CSV OP_DROP <p> OP_CHECKSIG
>
> and then decide <n> needs to be masked, you rewrite it as:
>
>     [n] OP_CSV OP_DROP <p> OP_CHECKSIG
>
> indicating n is masked, and don't worry about the exact bytes that will
> encode the push, anymore than you currently worry about whether it's
> OP_0, OP_1..16, <1..75>+1..75-bytes, PUSHDATA[1,2,3]+n+n-bytes.
>
> As long as OP_MASK only applies to a PUSH and it's an error for OP_MASK
> not to be immediately followed by that PUSH, I think that all works
> out fine.

Agreed, that makes more sense :-)


 permalink raw reply	[|nested]
2018-11-22 22:10         ` Russell O'Connor

  
From: Johnson Lau @ 2018-11-23 10:47 UTC (permalink / raw)
  To: Russell O'Connor;  bitcoin-dev

[-- Attachment #1: Type: text/plain, Size: 3604 bytes --]

>Even still, each call to OP_CODESEPARATOR / OP_CHECKSIG pair requires recomputing a new #5. scriptCode from BIP 143, and hence computes a new transaction digest.

In the existing sighash (i.e. legacy and BIP143), there are 6 canonical SIGHASH types: 1, 2, 3, 0x81, 0x82, 0x83. In consensus, however, all 256 types are valid and distinct. An adversarial miner could use non-standard sighash types to nullify any attempt to cache sighash values (i.e. you have to compute a new tx digest for every OP_CHECKSIG, even without using OP_CODESEPARATOR).

The only way to prevent this is reject OP_CODESEPARATOR, FindAndDelete(), and non-standard SIGHASH with a softfork. However, this doesn’t work in the next-generation SIGHASH, as tens of standard sighash types will exist. And, more importantly, sighash cache is no longer necessary in segwit, with the legacy O(n^2) hash bug being fixed.

In summary, sighash cache is not necessary nor efficient in the next-generation SIGHASH, and is not a sufficient reason to remove OP_CODESEPARATOR, especially when people find OP_CODESEPARATOR useful in some way.

But just to be clear, I think OP_CODESEPARATOR should be deprecated in legacy scripts. There is a general negative sentiment against OP_CODESEPARATOR but I think we need to evaluate case by case.

> On 23 Nov 2018, at 6:10 AM, Russell O'Connor <roconnor@blockstream•io> wrote:
> 
> 
> 
> On Thu, Nov 22, 2018 at 3:53 PM Johnson Lau <jl2012@xbt•hk <mailto:jl2012@xbt•hk>> wrote:
> Assuming a script size of 128 bytes (including SHA256 padding), 2^20 scripts is 134MB. Double it to 268MB for the merkle branch hashes. With roughly 100MB/s, this should take 2.5s (or 42min for 30 levels). However, memory use is not considered.
> 
> >each call to this operation effectively takes O(script-size) time
> I’m not sure if this is correct. Actually, CTransactionSignatureSerializer() scans every script for OP_CODESEPARATOR. Scripts with and without OP_CODESEPARATOR should take exactly the same O(script-size) time (see https://github.com/bitcoin/bitcoin/pull/14786 <https://github.com/bitcoin/bitcoin/pull/14786>)
> Also, this is no longer a concern under segwit (BIP143), which CTransactionSignatureSerializer() is not used. Actually, OP_CODESEPARATOR under segwit is way simpler than the proposed OP_MASK. If one finds OP_MASK acceptable, there should be no reason to reject OP_CODESEPARATOR.
> 
> Even still, each call to OP_CODESEPARATOR / OP_CHECKSIG pair requires recomputing a new #5. scriptCode from BIP 143, and hence computes a new transaction digest.  I understood that this issue was the main motivation for wanting to deprecate OP_CODESEPARATOR and remove it from later versions of script.
> 
> However, given that we are looking at a combinatorial explosion in SIGHASH flag combinations already, coupled with existing SigOp limitations, maybe the cost of recomputing scriptCode with OP_CODESEPARATOR isn't such a big deal.
> 
> And even if we choose remove the behavior of OP_CODESEPARATOR in new versions of Script, it seems more than 30 layers of sequential OP_IFs can be MASTified, so there is no need to use OP_CODESEPARATOR within that limit.
> 
> >One suggestion I heard (I think I heard it from Pieter) to achieve the above is to add an internal counter that increments on every control flow operator,……...
> If I have to choose among OP_CODESEPARATOR and “flow operator counting”, I’d rather choose OP_CODESEPARATOR. At least we don’t need to add more lines to the consensus code, just for something that is mostly archivable with MAST.
> 


[-- Attachment #2: Type: text/html, Size: 4989 bytes --]

 permalink raw reply	[|nested]
2018-11-23  5:03   ` Anthony Towns

  
From: Russell O'Connor @ 2018-11-23 20:18 UTC (permalink / raw)
  To: Anthony Towns;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 2158 bytes --]

On Fri, Nov 23, 2018 at 12:03 AM Anthony Towns <aj@erisian•com.au> wrote:

> On Wed, Nov 21, 2018 at 12:07:30PM -0500, Russell O'Connor via bitcoin-dev
> wrote:
> > Given that we want to move away from OP_CODESEPARATOR, because each call
> to
> > this operation effectively takes O(script-size) time, we need a
> replacement for
> > the functionality it currently provides.  While perhaps the original
> motivation
> > for OP_CODESEPARTOR is surrounded in mystery, it currently can be used
> (or
> > perhaps abused) for the task of creating signature that covers, not only
> which
> > input is being signed, but which specific branch within that input
> Script code
> > is being signed for.
>
> Would it be sufficient to sign the position within the script of the
> last OP_CODESEPARATOR? That is, if your script is:
>
> I think that covers all the behaviour you can currently achieve with
> CODESEP (which is pretty limited since every sig effectively commits
> to the full redeem script, and you can't commit to subsets of the
> signature/witness), and it keeps the things you can do with the various
> features a bit orthogonal:
>

Thanks for bringing this up.  I was thinking the same thing as well, that
yes that should be sufficient to cover the semantics of OP_CODESEPARATOR.
Though to be more precise you would sign the position of the last
_executed_ OP_CODESEPARATOR.

That said, while I agree the above is a superior realization of the
OP_CODESEPARATOR, given that we are probably going to support
OP_CODESEPARATOR inside legacy P2SH scripts indefinitely, it is probably
better to keep the existing akward implementation of OP_CODESEPARATOR in
future versions of Script.  (At least until we decide to stop mangling the
Script consensus code with more and more flag combinations and decide it is
better to cut and paste code for new versions of Script to help ensure we
don't make consensus changes to legacy behaviour).


> [0] (I think I'm going to claim "MAST" stands for "merkelized alternative
>      script tree" these days, since they're not "abstract syntax trees")
>

:thumbs-up:

Sorry for hijacking the thread about OP_MASK and friends.

[-- Attachment #2: Type: text/html, Size: 2757 bytes --]

 permalink raw reply	[|nested]
2018-11-23  9:40     ` Christian Decker

  
From: Johnson Lau @ 2018-11-24  8:13 UTC (permalink / raw)
  To: Christian Decker, bitcoin-dev



> On 23 Nov 2018, at 5:40 PM, Christian Decker via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> Anthony Towns <aj@erisian•com.au> writes:
>> Commiting to just the sequence numbers seems really weird to me; it
>> only really prevents you from adding inputs, since you could still
>> replace any input that was meant to be there by almost any arbitrary
>> other transaction...
> 
> It's a really roundabout way of committing to the inputs, I
> agree. I'm actually wondering if it makes sense to correct that
> additional blanked field in BIP118 at all since it seems there is no
> real use-case for NOINPUT that doesn't involve blanking the
> `hashSequence` as well.

I think we just make it as simple as this: Always commit to sequence of the same input. Commit to hashSequence if and only if all inputs and all outputs are signed.

The next-generation SIGHASH will introduce not only NOINPUT, but also signing of fees, previous scriptPubKey, and all input values, etc. So it won’t be a simple hack over BIP143. BIP118 might be better changed to be an informational BIP, focus on the rationale and examples of NOINPUT, and be cross-referenced with the consensus BIP.


 permalink raw reply	[|nested]
2018-11-28  8:40 ` Johnson Lau
  
From: Bob McElrath @ 2018-11-28  0:54 UTC (permalink / raw)
  To: Bitcoin Protocol Discussion

I have been working on an experimental wallet that implements Bitcoin
Covenants/Vaults following a blog post I wrote about 2 years ago, using
"Pay-to-Timelock Signed Transaction" (P2TST).  (Also mentioned recently by
kanzure in a talk somewheres...)  The idea is that you deposit to an address for
which you don't know the private key.  Instead you construct a second
transaction sending that to a timelocked staging address for which you DO have
the privkey (it also has an IF/ELSE condition with a second spending condition
for use in case of theft attempt).  In order to do this you either have to
delete the privkey of the deposit address (a difficult proposition to know it's
actually been deleted), but instead one can construct a signature directly using
a RNG, and use the SIGHASH to compute the corresponding pubkey via ECDSA
recover, from which you compute the corresponding address.  In this way your
wallet is a set of P2TST transactions and a corresponding privkey, with a (set
of) emergency keys.

This interacts with NOINPUT in the following way: if the input to the
transaction commits to the pubkey in any way, you have a circular dependency on
the pubkey that could only be satisfied by breaking a hash function.  This
occurs with standard sighash's which commit to the txid, which in turn commit to
the address, which commits to the pubkey, so this construction of
covenants/vaults requires NOINPUT.

AFAICT sipa's proposal is compatible with the above vaulted construction by
using SIGHASH_NOINPUT | SIGHASH_SCRIPTMASK to remove the
scriptPubKey/redeemScript from the sighash.  Putting the
scriptPubKey/redeemScript in the sighash introduces the same circular
dependency, but SIGHASH_SCRIPTMASK removes it.

One would probably want to provide the fee from a separate wallet so as to be
able to account for fluctuating fee pressures when the unvaulting occurs a long
time after vaulting.  Thus you'd want to use SIGHASH_SINGLE so that a fee-wallet
can add fees (or for composability of P2TSTs), and SIGHASH_NOFEE as well.

P.S. Also very excited to combine the above idea with Taproot/Graftroot/g'Root.

--
Cheers, Bob McElrath

"For every complex problem, there is a solution that is simple, neat, and wrong."
    -- H. L. Mencken 



 permalink raw reply	[|nested]
* 
  2018-11-19 22:37 Pieter Wuille
                   ` 
  2018-11-28  3:41 ` 

  2018-12-12 20:00   ` Johnson Lau
  2018-12-13  0:24   ` Anthony Towns
  4 siblings, 2 replies; 55+ messages in thread
From: Rusty Russell @ 2018-12-12  9:42 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion, Bitcoin Dev

Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
> Here is a combined proposal:
> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
> and SIGHASH_SCRIPTMASK.
> * A new opcode OP_MASK is added, which acts as a NOP during execution.
> * The sighash is computed like in BIP143, but:
>   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
> the subsequent opcode/push is removed.

I'm asking on-list because I'm sure I'm not the only confused one.

Having the SIGHASH_SCRIPTMASK flag is redundant AFAICT: why not always
perform mask-removal for signing?

If you're signing arbitrary scripts, you're surely in trouble already?

And I am struggling to understand the role of scriptmask in a taproot
world, where the alternate script is both hidden and general?

I look forward to learning what I missed!
Rusty.


^ permalink raw reply	[|nested] 55+ messages in thread
2018-11-28  3:41 ` Pieter Wuille

  2018-11-29 17:00   ` Christian Decker
  2018-12-06 16:57   ` Russell O'Connor
  
From: Johnson Lau @ 2018-11-28  8:31 UTC (permalink / raw)
  To: Pieter Wuille, bitcoin-dev

[-- Attachment #1: Type: text/plain, Size: 4204 bytes --]



> On 28 Nov 2018, at 11:41 AM, Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> So a combined proposal:
> * All existing sighash flags, plus NOINPUT and MASK
> (ANYONECANPAY/NOINPUT/MASK are encoded in 2 bits).
> * A new opcode called OP_MASKEDPUSH, whose only runtime behaviour is
> failing if not immediately followed by a push, or when appearing as
> last opcode in the script.

I suggest to use the place of OP_RESERVED (0x50) as OP_MASKEDPUSH. The reason is 0x50 is not counted towards the 201 opcode limit, so people could mask as many pushes as needed.

In a new script version, of course, we could make any opcode not being counted. But that would just create another special case in the EvalScript() code.

(Or, maybe we should limit the use of OP_MASKEDPUSH? I think this is open for discussion.)

> * Signatures are 64 plus an optional sighash byte. A missing sighash
> byte implies ALL, and ALL cannot be specified explicitly.
> * The sighash is computed from the following:
>  * A 64-byte constant tag
>  * Data about the spending transaction:
>    * The transaction version number
>    * The hash of txins' prevouts+amounts+sequences (or nothing if ANYONECANPAY)

Do you want to make it 1 hash or 3 hashes? With 3 hashes, it could share hashPrevouts and hashSequence with BIP143. Making everything 1 hash will only result in redundent hashing for each input

>    * The hash of all txouts (or just the corresponding txout if
> SINGLE; nothing if NONE)

Starting from this sighash version, I think we should forbid the use of SINGLE without a matching output. Also, the undefined output type should also be invalid.

>    * The transaction locktime
>  * Data about the output being spent:
>    * The prevout (or nothing if NOINPUT)
>    * The amount
>    * The sequence number
>    * The hash of the scriptPubKey (or nothing if MASK)

I think we should just use the scriptPubKey, since sPK is fixed size (23-byte for p2sh and 35-byte for native segwit).

In order to distinguish p2sh and native segwit for MASKED NOINPUT, you also need to commit to an additional 1-bit value

>  * Data about the script being executed:
>    * The hash of the scriptCode (after masking out, if MASK is set)

For direct key-spending (i.e. not taprooted script), I suggest to set the H(scriptCode) to zero, for the following reasons:
1) Since we have already committed to sPK, which is already a *direct* hash of scriptCode, it is redundant to do it again.
2) This could save one SHA256 compression for direct key-spending, which is probably 90% of all cases
3) This allows hardware wallet to tell whether they are using direct-spending path or taproot script path

Since we may want 3) anyway, we don’t need to commit to another 1-bit value if we simply set H(scriptCode) to zero

We should also ban MASKED NOINPUT for direct-spending, which doesn’t make sense. And it is not safe since both H(scriptCode) and sPK are empty.

>    * The opcode number of the last executed OP_CODESEPARATOR (or
> 0xFFFFFFFF if none)
>  * The sighash mode

This proposal will only use 4 out of the 8 sighash bits. Do we want to make those 4 unused bits invalid, or ignored? Leaving at least 1 bit valid but ignored (“bit-x"), and 1 bit invalid (“bit-y”), will allow opt-in/out hardfork replay-protection, for example:

* default signatures are those with both bit-x and bit-y unset.
* If we want to make default signatures replayable across chains, the new fork should reject signatures with bit-x, and accept sigs with or without bit-y. In this case, defaults sigs are valid for both chains. Sigs with bit-x is valid only for original chain, and sigs with bit-y is valid only for new chain.
* If we want to make default signatures non-replayabble, the new fork should reject all default sigs, but accept sigs with either bit-x or bit-y set. In this case, default sig is valid only for original chain. Sigs with bit-x is valid for both chains, and sigs with bit-y is valid only for new chain.

Replayability is sometimes desirable, for example, an LN opened before a fork should be able to be settled on both chains


[-- Attachment #2: Type: text/html, Size: 23919 bytes --]

 permalink raw reply	[|nested]
2018-11-28  0:54 [bitcoin-dev] Safer sighashes and more granular SIGHASH_NOINPUT Bob McElrath

  2018-11-28 14:04   ` Bob McElrath
  
From: Johnson Lau @ 2018-11-28  8:40 UTC (permalink / raw)
  To: Bob McElrath, bitcoin-dev

This is incompatible with bip-schnorr, which intentionally disallow such use by always committing to the public key: https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki

With the recent fake Satoshi signature drama, and other potential ways to misuse and abuse, I think this is a better way to go, which unfortunately might disallow some legitimate applications.

Covenants could be made using OP_CHECKSIGFROMSTACK (https://fc17.ifca.ai/bitcoin/papers/bitcoin17-final28.pdf) or OP_PUSHTXDATA (https://github.com/jl2012/bips/blob/vault/bip-0ZZZ.mediawiki). I think this is the next step following the taproot soft fork

> On 28 Nov 2018, at 8:54 AM, Bob McElrath via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> I have been working on an experimental wallet that implements Bitcoin
> Covenants/Vaults following a blog post I wrote about 2 years ago, using
> "Pay-to-Timelock Signed Transaction" (P2TST).  (Also mentioned recently by
> kanzure in a talk somewheres...)  The idea is that you deposit to an address for
> which you don't know the private key.  Instead you construct a second
> transaction sending that to a timelocked staging address for which you DO have
> the privkey (it also has an IF/ELSE condition with a second spending condition
> for use in case of theft attempt).  In order to do this you either have to
> delete the privkey of the deposit address (a difficult proposition to know it's
> actually been deleted), but instead one can construct a signature directly using
> a RNG, and use the SIGHASH to compute the corresponding pubkey via ECDSA
> recover, from which you compute the corresponding address.  In this way your
> wallet is a set of P2TST transactions and a corresponding privkey, with a (set
> of) emergency keys.
> 
> This interacts with NOINPUT in the following way: if the input to the
> transaction commits to the pubkey in any way, you have a circular dependency on
> the pubkey that could only be satisfied by breaking a hash function.  This
> occurs with standard sighash's which commit to the txid, which in turn commit to
> the address, which commits to the pubkey, so this construction of
> covenants/vaults requires NOINPUT.
> 
> AFAICT sipa's proposal is compatible with the above vaulted construction by
> using SIGHASH_NOINPUT | SIGHASH_SCRIPTMASK to remove the
> scriptPubKey/redeemScript from the sighash.  Putting the
> scriptPubKey/redeemScript in the sighash introduces the same circular
> dependency, but SIGHASH_SCRIPTMASK removes it.
> 
> One would probably want to provide the fee from a separate wallet so as to be
> able to account for fluctuating fee pressures when the unvaulting occurs a long
> time after vaulting.  Thus you'd want to use SIGHASH_SINGLE so that a fee-wallet
> can add fees (or for composability of P2TSTs), and SIGHASH_NOFEE as well.
> 
> P.S. Also very excited to combine the above idea with Taproot/Graftroot/g'Root.
> 
> --
> Cheers, Bob McElrath
> 
> "For every complex problem, there is a solution that is simple, neat, and wrong."
>    -- H. L. Mencken 
> 
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev




 permalink raw reply	[|nested]
2018-11-28  8:40 ` Johnson Lau

  
From: Bob McElrath @ 2018-11-28 14:04 UTC ( / )
  To: Johnson Lau;  bitcoin-dev

We are also prototyping the OP_CHECKSIGFROMSTACK mechanism using Liquid/Elements.

Given uncertainty about which features will actually be deployed on mainnet,
we're exploring all possibilities so as to provide feedback about the "best" way
to implement a covenant/vault, also including the OP_CHECKOUTPUTVERIFY
originally proposed by Eyal et al. That's 3 ways to implement a covenant/vault,
if there's others I'd be happy to hear about it.  ;-)  Thanks for the
OP_PUSHTXDATA ref, I'm reading now...  Personally I think the
OP_CHECKSIGFROMSTACK is probably the most elegant mechanism.

Thanks for the feedback!

Johnson Lau [jl2012@xbt•hk] wrote:
> This is incompatible with bip-schnorr, which intentionally disallow such use by always committing to the public key: https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki
> 
> With the recent fake Satoshi signature drama, and other potential ways to misuse and abuse, I think this is a better way to go, which unfortunately might disallow some legitimate applications.
> 
> Covenants could be made using OP_CHECKSIGFROMSTACK (https://fc17.ifca.ai/bitcoin/papers/bitcoin17-final28.pdf) or OP_PUSHTXDATA (https://github.com/jl2012/bips/blob/vault/bip-0ZZZ.mediawiki). I think this is the next step following the taproot soft fork
> 
> > On 28 Nov 2018, at 8:54 AM, Bob McElrath via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> > 
> > I have been working on an experimental wallet that implements Bitcoin
> > Covenants/Vaults following a blog post I wrote about 2 years ago, using
> > "Pay-to-Timelock Signed Transaction" (P2TST).  (Also mentioned recently by
> > kanzure in a talk somewheres...)  The idea is that you deposit to an address for
> > which you don't know the private key.  Instead you construct a second
> > transaction sending that to a timelocked staging address for which you DO have
> > the privkey (it also has an IF/ELSE condition with a second spending condition
> > for use in case of theft attempt).  In order to do this you either have to
> > delete the privkey of the deposit address (a difficult proposition to know it's
> > actually been deleted), but instead one can construct a signature directly using
> > a RNG, and use the SIGHASH to compute the corresponding pubkey via ECDSA
> > recover, from which you compute the corresponding address.  In this way your
> > wallet is a set of P2TST transactions and a corresponding privkey, with a (set
> > of) emergency keys.
> > 
> > This interacts with NOINPUT in the following way: if the input to the
> > transaction commits to the pubkey in any way, you have a circular dependency on
> > the pubkey that could only be satisfied by breaking a hash function.  This
> > occurs with standard sighash's which commit to the txid, which in turn commit to
> > the address, which commits to the pubkey, so this construction of
> > covenants/vaults requires NOINPUT.
> > 
> > AFAICT sipa's proposal is compatible with the above vaulted construction by
> > using SIGHASH_NOINPUT | SIGHASH_SCRIPTMASK to remove the
> > scriptPubKey/redeemScript from the sighash.  Putting the
> > scriptPubKey/redeemScript in the sighash introduces the same circular
> > dependency, but SIGHASH_SCRIPTMASK removes it.
> > 
> > One would probably want to provide the fee from a separate wallet so as to be
> > able to account for fluctuating fee pressures when the unvaulting occurs a long
> > time after vaulting.  Thus you'd want to use SIGHASH_SINGLE so that a fee-wallet
> > can add fees (or for composability of P2TSTs), and SIGHASH_NOFEE as well.
> > 
> > P.S. Also very excited to combine the above idea with Taproot/Graftroot/g'Root.
> > 
> > --
> > Cheers, Bob McElrath
> > 
> > "For every complex problem, there is a solution that is simple, neat, and wrong."
> >    -- H. L. Mencken 
> > 
> > _______________________________________________
> > bitcoin-dev mailing list
> > bitcoin-dev@lists•linuxfoundation.org
> > https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
> 
> 
> 
> 
> !DSPAM:5bfe5494217527839717631!
--
Cheers, Bob McElrath

"For every complex problem, there is a solution that is simple, neat, and wrong."
    -- H. L. Mencken
2018-11-28  3:41 ` Pieter Wuille
  2018-11-28  8:31   ` Johnson Lau

  2018-11-29 18:29     ` Christian Decker
  2018-12-06 16:57   ` Russell O'Connor
  
From: Christian Decker @ 2018-11-29 17:00 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion, Bitcoin Dev

Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org>
writes:

> On Mon, 19 Nov 2018 at 14:37, Pieter Wuille <pieter.wuille@gmail•com> wrote:
> * It's probably better to sign the amounts of all inputs, as suggested
> by Johnson Lau. As that would cause default sighashes to sign all
> input and output amounts, is there still a need to sign the tx fee
> explicitly? Or in other words, are there situations where changing the
> set of inputs or outputs after signing is desired, but the net
> difference between them cannot change? If not, that would remove the
> need for NOFEE.

So the final proposal would be to append a new `hashValues` field to the
hashed representation, with `hashValues` just being the double SHA256 of
all values? In that case SINGLE needs to blank that hash, otherwise we'd
be committing to all inputs again.

Once we have that detail, we can start thinking about what it means to
commit to the fee vs. committing to the values. Since the fee is given
by the output values and the input values we only need to consider the
cases in which they can be modified.

 - NOINPUT (as in BIP118) commits to the value (and I can't think of a
   usecase where we'd want to change that), and that transparently
   extends to all other inputs.
 - For ANYONECANPAY can't really commit to a fee anyway so ANYONECANPAY
   would likely imply NOFEE.
 - With NONE all bets are off anyway, so no need to consider that :-)
 - SINGLE is a bit special, and for value commitments it reduces to the
   current commitment to its own value, for fee commitment it's hard to
   see a use of that commitment at all afaik (I think the combination
   SINGLE|NOFEE would always be used).

> * Do we need to keep the rule that sequence values of other inputs are
> only signed with default sighash? It feels cleaner to always sign the
> sequence values of all inputs that are included in the sighash anyway
> (so all of them, unless ANYONECANPAY or NOINPUT, which would make it
> sign only the current input's sequence value). If NOINPUT also blanks
> the sequence values (as currently specified by BIP118), and all input
> amounts are signed, that would make amounts/sequence values always be
> treated identically.

Single cannot commit to other the sequence of other inputs, otherwise
we're breaking SINGLE completely. As mentioned before NOINPUT doesn't
need to blank `hashSequence`, but I'm happy to make it match if that
makes implementations handle fewer cases.

> * If MASK implies NOINPUT, and NOINPUT implies ANYONECANPAY, the 3 of
> them can be encoded in just 2 bits using the
> PARTIALSCRIPT/KNOWNSCRIPT/KNOWNTX/ALL_INPUTS encoding Anthony Towns
> suggested.

So we'd end up enumerating the combinations rather than having
independent bits for each of them? This might save us storage bits, but
it'd also result in uglier code imho, not a strong feeling but might
come back to haunt us if we ever come up with something new :-)

> So a combined proposal:
> * All existing sighash flags, plus NOINPUT and MASK
> (ANYONECANPAY/NOINPUT/MASK are encoded in 2 bits).
> * A new opcode called OP_MASKEDPUSH, whose only runtime behaviour is
> failing if not immediately followed by a push, or when appearing as
> last opcode in the script.
> * Signatures are 64 plus an optional sighash byte. A missing sighash
> byte implies ALL, and ALL cannot be specified explicitly.
> * The sighash is computed from the following:
>   * A 64-byte constant tag
>   * Data about the spending transaction:
>     * The transaction version number
>     * The hash of txins' prevouts+amounts+sequences (or nothing if ANYONECANPAY)

This needs to be partially blanked for SINGLE as well, otherwise we
break SINGLE.

>     * The hash of all txouts (or just the corresponding txout if
> SINGLE; nothing if NONE)
>     * The transaction locktime
>   * Data about the output being spent:
>     * The prevout (or nothing if NOINPUT)
>     * The amount
>     * The sequence number

I assume the sequence number here refers to the input being signed, not
the sequence number of the transaction output being spent :-) Might be
easier if we consider 3 parts: the spending transaction, the input being
signed, and the output (or TX) being spent.

Cheers,
Christian


 permalink raw reply	[|nested]
2018-11-29 17:00   ` Christian Decker

  
From: Christian Decker @ 2018-11-29 18:29 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion, Bitcoin Dev

I'd like to retract my comments regarding SINGLE.

I was contacted in private and it was pointed out to me that I was
confusing `sighash_single` with `sighash_single|sighash_anyonecanpay`. I
appreciate the correction and would like to avoid creating confusion
with my previous comments, hence the retraction :-)

Cheers,
Christian


 permalink raw reply	[|nested]
2018-11-28  3:41 ` Pieter Wuille
  2018-11-28  8:31   ` Johnson Lau
  2018-11-29 17:00   ` Christian Decker

  2018-12-09 19:13     ` Johnson Lau
  2018-12-09 22:41     ` David A. Harding
  
From: Russell O'Connor @ 2018-12-06 16:57 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 8004 bytes --]

One more item to consider is "signature covers witness weight".

While signing the witness weight doesn't completely eliminate witness
malleability (of the kind that can cause grief for compact blocks), it does
eliminate the worst kind of witness malleability from the user's
perspective, the kind where malicious relay nodes increase the amount of
witness data and therefore reduce the overall fee-rate of the transaction.
Generally users should strive to construct their Bitcoin Scripts in such a
way that witness malleability isn't possible, but as you are probably
aware, this can be quite difficult to achieve as Scripts become more
complex and maybe isn't even possible for some complex Scripts.

Given the new fixed-sized signature of the Schnorr BIP, it becomes much
easier to compute the final witness weight prior to signing.  In complex
multi-party signing protocol, the final witness weight might not be known
at signing time for everyone involved, so the "signature covers witness
weight" ought to be optional.


On Tue, Nov 27, 2018 at 11:59 PM Pieter Wuille via bitcoin-dev <
bitcoin-dev@lists•linuxfoundation.org> wrote:

> On Mon, 19 Nov 2018 at 14:37, Pieter Wuille <pieter.wuille@gmail•com>
> wrote:
> > Here is a combined proposal:
> > * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE, and
> SIGHASH_SCRIPTMASK.
> > * A new opcode OP_MASK is added, which acts as a NOP during execution.
> > * The sighash is computed like in BIP143, but:
> >   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
> the subsequent opcode/push is removed.
> >   * The scriptPubKey being spent is added to the sighash, unless
> SIGHASH_SCRIPTMASK is set.
> >   * The transaction fee is added to the sighash, unless SIGHASH_NOFEE is
> set.
> >   * hashPrevouts, hashSequence, and outpoint are set to null when
> SIGHASH_NOINPUT is set (like BIP118, but not for scriptCode).
>
> Thanks for all the input so far. Going over the suggestions and other
> ideas:
>
> * OP_MASK should be required to be followed by a push, as suggested by
> Anthony Towns. The alternative would permit substituting arbitrary
> opcodes for masked pushes, which is at least very hard to reason
> about. This would effectively turn it into a multi-byte OP_MASKEDPUSH
> opcode.
>
> * It's probably better to sign the amounts of all inputs, as suggested
> by Johnson Lau. As that would cause default sighashes to sign all
> input and output amounts, is there still a need to sign the tx fee
> explicitly? Or in other words, are there situations where changing the
> set of inputs or outputs after signing is desired, but the net
> difference between them cannot change? If not, that would remove the
> need for NOFEE.
>
> * Do we need to keep the rule that sequence values of other inputs are
> only signed with default sighash? It feels cleaner to always sign the
> sequence values of all inputs that are included in the sighash anyway
> (so all of them, unless ANYONECANPAY or NOINPUT, which would make it
> sign only the current input's sequence value). If NOINPUT also blanks
> the sequence values (as currently specified by BIP118), and all input
> amounts are signed, that would make amounts/sequence values always be
> treated identically.
>
> * If MASK implies NOINPUT, and NOINPUT implies ANYONECANPAY, the 3 of
> them can be encoded in just 2 bits using the
> PARTIALSCRIPT/KNOWNSCRIPT/KNOWNTX/ALL_INPUTS encoding Anthony Towns
> suggested.
>
> * Regarding the discussion about preventing signatures from being
> rebound to a different script(path)/checksig:
>   * With MAST there is indeed less need for this, but at least
> single-tree MAST constructions cannot replace all script branches (a
> script with 40 IF/THEN/ELSE constructions may have 2^40 different
> execution paths, for which computing a Merkle tree is intractable).
>   * Just signing the opcode position of the CHECKSIG operator isn't
> enough for all cases either. For example, you could have a complex
> nested set of branches that puts a number of pubkeys on the stack, and
> then a CHECKMULTISIG after the last ENDIF to verify all of them. In
> such a situation, if the same key can occur in multiple combinations,
> you still may want to prevent a signature generated for one
> combination from being rebindable to the same key in another
> combination. I believe that signing the opcode position plus the
> true/false condition of all previous(?) IF statements is probably
> sufficient to achieve that, but it would also introduce unnecessary
> complexity for signers in most cases (see next point).
>   * Thinking about signing code, adding these sort of execution trace
> commitments to the sighash means they need to know which checksig
> operator etc. they are signing for. I believe that in practice for
> example HW devices will just whatever position the wallet indicated,
> rather than verifying it corresponds with a particular intended code
> path. Preventing rebinding isn't very useful if an attacker can make
> you bind to the wrong thing regardless, so I'm not convinced this is
> even worth having by default.
>   * An alternative (not sure who suggested it) is to simply make every
> CHECKSIG sign the opcode position of the last executed CODESEPARATOR
> (and remove the earlier cut-of-scriptCode effect of CODESEPARATOR).
> This gives a simple (but somewhat limited) way for scripts that need
> to prevent certain kinds of cross-execution-trace rebinding.
>
> A few misc ideas:
> * (Taken from
> https://github.com/jl2012/bips/blob/sighash2/bip-sighash2.mediawiki)
> For a default sign-everything sighash, the sighash byte can be
> dropped.
> * For the commitments to the scriptPubKey and scriptCode, an
> intermediary hash should be used (so the data included in the sighash
> includes a hash of those, rather than the script directly). This
> prevents a blow up in hashing time for large scripts with many
> different sighash types in its signatures.
> * When masking the scriptCode, the push opcode immediately following
> OP_MASKEDPUSH can be replaced by OP_VERIF (which will never collide
> with any real script, as OP_VERIF makes a script invalid even when
> occurring in an unexecuted branch).
> * Sighashes (and really all new hashes that are introduced) should be
> prefixed with a fixed 64-byte array as "tag", chosen to not collide
> with any existing use of SHA256 in Bitcoin, to prevent signatures from
> being re-interpretable as something else. Picking 64 bytes as tag size
> means it can be efficiently implemented as just a modified SHA256 IV.
>
> So a combined proposal:
> * All existing sighash flags, plus NOINPUT and MASK
> (ANYONECANPAY/NOINPUT/MASK are encoded in 2 bits).
> * A new opcode called OP_MASKEDPUSH, whose only runtime behaviour is
> failing if not immediately followed by a push, or when appearing as
> last opcode in the script.
> * Signatures are 64 plus an optional sighash byte. A missing sighash
> byte implies ALL, and ALL cannot be specified explicitly.
> * The sighash is computed from the following:
>   * A 64-byte constant tag
>   * Data about the spending transaction:
>     * The transaction version number
>     * The hash of txins' prevouts+amounts+sequences (or nothing if
> ANYONECANPAY)
>     * The hash of all txouts (or just the corresponding txout if
> SINGLE; nothing if NONE)
>     * The transaction locktime
>   * Data about the output being spent:
>     * The prevout (or nothing if NOINPUT)
>     * The amount
>     * The sequence number
>     * The hash of the scriptPubKey (or nothing if MASK)
>   * Data about the script being executed:
>     * The hash of the scriptCode (after masking out, if MASK is set)
>     * The opcode number of the last executed OP_CODESEPARATOR (or
> 0xFFFFFFFF if none)
>   * The sighash mode
>
> Cheers,
>
> --
> Pieter
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>

[-- Attachment #2: Type: text/html, Size: 9195 bytes --]

 permalink raw reply	[|nested]
2018-12-06 16:57   ` Russell O'Connor

  2018-12-11 22:50       ` Russell O'Connor
  2018-12-09 22:41     ` David A. Harding
  
From: Johnson Lau @ 2018-12-09 19:13 UTC (permalink / raw)
  To: Russell O'Connor, bitcoin-dev

The current proposal is that a 64-byte signature will be used for the default “signing all” sighash, and 65-byte for other sighash types. The space saved will allow a few more txs in a block, so I think it worths doing. However, this also makes witness weight estimation more difficult in multisig cases.

This idea of signing witness weight has been brought up before. I think the concern is the difficulty to estimate the witness weight for complex scripts, which need this feature most. So it will work when it is not needed, and will not work when it is needed.

Is there any script example that witness size malleability is unavoidable?

> On 7 Dec 2018, at 12:57 AM, Russell O'Connor via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> One more item to consider is "signature covers witness weight".
> 
> While signing the witness weight doesn't completely eliminate witness malleability (of the kind that can cause grief for compact blocks), it does eliminate the worst kind of witness malleability from the user's perspective, the kind where malicious relay nodes increase the amount of witness data and therefore reduce the overall fee-rate of the transaction.  Generally users should strive to construct their Bitcoin Scripts in such a way that witness malleability isn't possible, but as you are probably aware, this can be quite difficult to achieve as Scripts become more complex and maybe isn't even possible for some complex Scripts.
> 
> Given the new fixed-sized signature of the Schnorr BIP, it becomes much easier to compute the final witness weight prior to signing.  In complex multi-party signing protocol, the final witness weight might not be known at signing time for everyone involved, so the "signature covers witness weight" ought to be optional.
> 
> 




 permalink raw reply	[|nested]
2018-12-06 16:57   ` Russell O'Connor
  2018-12-09 19:13     ` Johnson Lau

  2018-12-11 15:36       ` Russell O'Connor
  
From: David A. Harding @ 2018-12-09 22:41 UTC (permalink / raw)
  To: Russell O'Connor, Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 1158 bytes --]

On Thu, Dec 06, 2018 at 11:57:09AM -0500, Russell O'Connor via bitcoin-dev wrote:
> One more item to consider is "signature covers witness weight".
> 
> While signing the witness weight doesn't completely eliminate witness
> malleability (of the kind that can cause grief for compact blocks), it does
> eliminate the worst kind of witness malleability from the user's
> perspective, the kind where malicious relay nodes increase the amount of
> witness data and therefore reduce the overall fee-rate of the transaction.

To what degree is this an actual problem?  If the mutated transaction
pays a feerate at least incremental-relay-fee[1] below the original
transaction, then the original transaction can be rebroadcast as an RBF
replacement of the mutated transaction (unless the mutated version has
been pinned[2]).

-Dave

[1] $ bitcoind -help-debug | grep -A2 incremental
  -incrementalrelayfee=<amt>
       Fee rate (in BTC/kB) used to define cost of relay, used for mempool
       limiting and BIP 125 replacement. (default: 0.00001)

[2] https://bitcoin.stackexchange.com/questions/80803/what-is-meant-by-transaction-pinning


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

 permalink raw reply	[|nested]
2018-12-09 22:41     ` David A. Harding

  2018-12-11 17:47         ` David A. Harding
  
From: Russell O'Connor @ 2018-12-11 15:36 UTC (permalink / raw)
  To: dave;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 1830 bytes --]

I don't believe that the default RBF policy works that way.  My
understanding is that current policy requires an absolute fee increase (by
an amount related to incrementalrelayfee).  There have been proposals to
change default RBF policy, however even my proposal <
https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-February/015717.html>
still requires a minimal amount of absolute fee increase as a DoS defense.

(I'm reading your comment as attempting to rebroadcast the original
transaction with the same fee amount, with its relatively higher fee-rate).

On Mon, Dec 10, 2018 at 10:00 AM David A. Harding <dave@dtrt•org> wrote:

> On Thu, Dec 06, 2018 at 11:57:09AM -0500, Russell O'Connor via bitcoin-dev
> wrote:
> > One more item to consider is "signature covers witness weight".
> >
> > While signing the witness weight doesn't completely eliminate witness
> > malleability (of the kind that can cause grief for compact blocks), it
> does
> > eliminate the worst kind of witness malleability from the user's
> > perspective, the kind where malicious relay nodes increase the amount of
> > witness data and therefore reduce the overall fee-rate of the
> transaction.
>
> To what degree is this an actual problem?  If the mutated transaction
> pays a feerate at least incremental-relay-fee[1] below the original
> transaction, then the original transaction can be rebroadcast as an RBF
> replacement of the mutated transaction (unless the mutated version has
> been pinned[2]).
>
> -Dave
>
> [1] $ bitcoind -help-debug | grep -A2 incremental
>   -incrementalrelayfee=<amt>
>        Fee rate (in BTC/kB) used to define cost of relay, used for mempool
>        limiting and BIP 125 replacement. (default: 0.00001)
>
> [2]
> https://bitcoin.stackexchange.com/questions/80803/what-is-meant-by-transaction-pinning
>
>

[-- Attachment #2: Type: text/html, Size: 2547 bytes --]

 permalink raw reply	[|nested]
2018-12-11 15:36       ` Russell O'Connor

  
From: David A. Harding @ 2018-12-11 17:47 UTC (permalink / raw)
  To: Russell O'Connor;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]

On Tue, Dec 11, 2018 at 10:36:59AM -0500, Russell O'Connor wrote:
> I don't believe that the default RBF policy works that way.  My
> understanding is that current policy requires an absolute fee increase (by
> an amount related to incrementalrelayfee).  

Indeed, you are correct (BIP125 rule 4[1]).

Thanks for the correction,

-Dave

[1] For the curious, the relevant code from master's validation.cpp:

    // Finally in addition to paying more fees than the conflicts the
    // new transaction must pay for its own bandwidth.
    CAmount nDeltaFees = nModifiedFees - nConflictingFees;
    if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
    {
        return state.DoS(0, false,
                REJECT_INSUFFICIENTFEE, "insufficient fee", false,
                strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
                      hash.ToString(),
                      FormatMoney(nDeltaFees),
                      FormatMoney(::incrementalRelayFee.GetFee(nSize))));
    }

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

 permalink raw reply	[|nested]
2018-12-09 19:13     ` Johnson Lau

  2018-12-12 19:53         ` Johnson Lau
                           ` (2 more replies)
  
From: Russell O'Connor @ 2018-12-11 22:50 UTC (permalink / raw)
  To: Johnson Lau;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 3326 bytes --]

On Sun, Dec 9, 2018 at 2:13 PM Johnson Lau <jl2012@xbt•hk> wrote:

> The current proposal is that a 64-byte signature will be used for the
> default “signing all” sighash, and 65-byte for other sighash types. The
> space saved will allow a few more txs in a block, so I think it worths
> doing. However, this also makes witness weight estimation more difficult in
> multisig cases.
>
> This idea of signing witness weight has been brought up before. I think
> the concern is the difficulty to estimate the witness weight for complex
> scripts, which need this feature most. So it will work when it is not
> needed, and will not work when it is needed.
>
> Is there any script example that witness size malleability is unavoidable?
>

I tend to think in opposite terms. Is there a proof that any script can be
transformed into an equivalent one that avoids witness weight
malleability?   But I admit there is a trade off:  If we don't allow for
signature covers weight, and we do need it, it will be too late to add.  On
the other hand if we add signature covers weight, but it turns out that no
Script ever needs to use it, then we've added that software complexity for
no gain.  However, I think the software complexity is relatively low,
making it worthwhile.

Moreover, even if witness weight malleability is entirely avoidable, it
always seems to come at a cost.  Taking as an example libwally's proposed "
<https://github.com/ElementsProject/libwally-core/blob/c6db6ccdfa54571afeeb582919240263424736a2/src/script.c#L718-L735>csv_2of3_then_2"
Script
<https://github.com/ElementsProject/libwally-core/blob/c6db6ccdfa54571afeeb582919240263424736a2/src/script.c#L718-L735>,
it begins with "OP_DEPTH OP_1SUB OP_1SUB" spending 3 vbytes to avoid any
possible witness malleability versus just taking a witness stack item to
determine the branch, costing 1 or 2 (unmalleated) vbytes.  Now to be fair,
under Taproot this particular script's witness malleability problem
probably goes away.  Nonetheless, I think it is fair to say that Bitcoin
Script was designed without any regard given to scriptSig/witness
malleability concerns and the result is that one is constantly fighting
against malleability issues.  Short of a wholesale replacement of Bitcoin
Script, I do think that having an option for signature covers weight is one
of the best ways to address the whole problem.

Regarding your point about 64/65-byte signatures; I speculate that in most
protocols, all parties that are able to consider signing the weight, know
what sighash flags the other parties are expected to be using.  However,
your point is well-taken, and if we choose to adopt the option of
signatures covering weight, we ought to make sure there exists a 65-byte
signature that performs the equivalent of a sigHashAll (of course, still
covering that particular sighash flag under the signature), to ensure that
anti-weight-malleability can be use even when the sighash flags that other
parties will use are unknown.  Even with the extra vbytes in the
signatures, there may be a net weight savings by avoiding the need for
anti-malleability Script code. (It might also be reasonable to have
participants create signatures for a small range of different weight
values? (Sorry in advance to PSBT)).

[-- Attachment #2: Type: text/html, Size: 3846 bytes --]

 permalink raw reply	[|nested]
2018-11-19 22:37 Pieter Wuille
                   ` 
  2018-11-28  3:41 ` 

  2018-12-12 20:00   ` Johnson Lau
  2018-12-13  0:24   ` Anthony Towns
  
From: Rusty Russell @ 2018-12-12  9:42 UTC (permalink / raw)
  To: Pieter Wuille, Bitcoin Protocol Discussion, Bitcoin Dev

Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
> Here is a combined proposal:
> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
> and SIGHASH_SCRIPTMASK.
> * A new opcode OP_MASK is added, which acts as a NOP during execution.
> * The sighash is computed like in BIP143, but:
>   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
> the subsequent opcode/push is removed.

I'm asking on-list because I'm sure I'm not the only confused one.

Having the SIGHASH_SCRIPTMASK flag is redundant AFAICT: why not always
perform mask-removal for signing?

If you're signing arbitrary scripts, you're surely in trouble already?

And I am struggling to understand the role of scriptmask in a taproot
world, where the alternate script is both hidden and general?

I look forward to learning what I missed!
Rusty.


 permalink raw reply	[|nested]
2018-12-11 22:50       ` Russell O'Connor

  2018-12-13 16:50           ` Russell O'Connor
  2018-12-13  0:05         ` Anthony Towns
       [not found]         ` <CAAS2fgRma+Pw-rHJSOKRVBqoxqJ3AxHO9d696fWoa-sb17JEOQ@mail.gmail.com>
  
From: Johnson Lau @ 2018-12-12 19:53 UTC (permalink / raw)
  To: Russell O'Connor;  bitcoin-dev

[-- Attachment #1: Type: text/plain, Size: 4692 bytes --]



> On 12 Dec 2018, at 6:50 AM, Russell O'Connor <roconnor@blockstream•io> wrote:
> 
> On Sun, Dec 9, 2018 at 2:13 PM Johnson Lau <jl2012@xbt•hk <mailto:jl2012@xbt•hk>> wrote:
> The current proposal is that a 64-byte signature will be used for the default “signing all” sighash, and 65-byte for other sighash types. The space saved will allow a few more txs in a block, so I think it worths doing. However, this also makes witness weight estimation more difficult in multisig cases.
> 
> This idea of signing witness weight has been brought up before. I think the concern is the difficulty to estimate the witness weight for complex scripts, which need this feature most. So it will work when it is not needed, and will not work when it is needed.
> 
> Is there any script example that witness size malleability is unavoidable?
> 
> I tend to think in opposite terms. Is there a proof that any script can be transformed into an equivalent one that avoids witness weight malleability?   But I admit there is a trade off:  If we don't allow for signature covers weight, and we do need it, it will be too late to add.  On the other hand if we add signature covers weight, but it turns out that no Script ever needs to use it, then we've added that software complexity for no gain.  However, I think the software complexity is relatively low, making it worthwhile.
> 
> Moreover, even if witness weight malleability is entirely avoidable, it always seems to come at a cost.  Taking as an example libwally's proposed " <https://github.com/ElementsProject/libwally-core/blob/c6db6ccdfa54571afeeb582919240263424736a2/src/script.c#L718-L735>csv_2of3_then_2" Script <https://github.com/ElementsProject/libwally-core/blob/c6db6ccdfa54571afeeb582919240263424736a2/src/script.c#L718-L735>, it begins with "OP_DEPTH OP_1SUB OP_1SUB" spending 3 vbytes to avoid any possible witness malleability versus just taking a witness stack item to determine the branch, costing 1 or 2 (unmalleated) vbytes.  Now to be fair, under Taproot this particular script's witness malleability problem probably goes away.  Nonetheless, I think it is fair to say that Bitcoin Script was designed without any regard given to scriptSig/witness malleability concerns and the result is that one is constantly fighting against malleability issues.  Short of a wholesale replacement of Bitcoin Script, I do think that having an option for signature covers weight is one of the best ways to address the whole problem.
> 
> Regarding your point about 64/65-byte signatures; I speculate that in most protocols, all parties that are able to consider signing the weight, know what sighash flags the other parties are expected to be using.  However, your point is well-taken, and if we choose to adopt the option of signatures covering weight, we ought to make sure there exists a 65-byte signature that performs the equivalent of a sigHashAll (of course, still covering that particular sighash flag under the signature), to ensure that anti-weight-malleability can be use even when the sighash flags that other parties will use are unknown.  Even with the extra vbytes in the signatures, there may be a net weight savings by avoiding the need for anti-malleability Script code. (It might also be reasonable to have participants create signatures for a small range of different weight values? (Sorry in advance to PSBT)).

I think the root cause of witness weight malleability is some opcodes accept variable size input (without affecting the output), and that input is provided by the puzzle solver. Going through the opcode list, I think such opcodes include IF, NOTIF, VERIFY, DROP, 2DROP, NIP, DEPTH, and all arithmetic opcode that accepts CScriptNum (including CHECKMULTISIG)

VERIFY, DROP, 2DROP, NIP are not real problem, since they should not be the first opcode to interact with data directly provided by the puzzle solver.

CHECKMULTISIG is fixed by BIP147. For the key number and sig number, they should be part of the script, so not malleable.

DEPTH is a problem only if its inputs are not later examined by other opcodes. Again, this is pointless.

The liberally example should be protected by the MINIMAL_IF policy, which requires the input of OP_IF be minimal. As you note, OP_IF could be replaced by taproot in many cases

Non-minimal CScriptNum is also banned as BIP62 policy.

For the purpose of preventing malicious third party witness bloating, all we need is the miners to enforce the policy. There is no reason for miners to accept size malleated txs, as that will reduce the usable block space. If they hate a tx, they would simply drop it, instead of wasting the block space.



[-- Attachment #2: Type: text/html, Size: 6226 bytes --]

 permalink raw reply	[|nested]
2018-12-12  9:42 ` Rusty Russell

  2018-12-12 23:49     ` Rusty Russell
  2018-12-13  0:24   ` Anthony Towns
  
From: Johnson Lau @ 2018-12-12 20:00 UTC (permalink / raw)
  To: Rusty Russell, bitcoin-dev



> On 12 Dec 2018, at 5:42 PM, Rusty Russell via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
>> Here is a combined proposal:
>> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
>> and SIGHASH_SCRIPTMASK.
>> * A new opcode OP_MASK is added, which acts as a NOP during execution.
>> * The sighash is computed like in BIP143, but:
>>  * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
>> the subsequent opcode/push is removed.
> 
> I'm asking on-list because I'm sure I'm not the only confused one.
> 
> Having the SIGHASH_SCRIPTMASK flag is redundant AFAICT: why not always
> perform mask-removal for signing?

Because a hardware wallet may want to know what exact script it is signing?

Masked script has reduced security, but this is a tradeoff with functionality (e.g. eltoo can’t work without masking part of the script). So when you don’t need that extra functionality, you go back to better security

However, I’m not sure if there is any useful NOINPUT case with unmasked script.

> 
> If you're signing arbitrary scripts, you're surely in trouble already?
> 
> And I am struggling to understand the role of scriptmask in a taproot
> world, where the alternate script is both hidden and general?

It makes sure that your signature is applicable to a specific script branch, not others (assuming you use the same pubkey in many branches, which is avoidable)

> 
> I look forward to learning what I missed!
> Rusty.
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev




 permalink raw reply	[|nested]
2018-12-12 20:00   ` Johnson Lau

  2018-12-13  0:37       ` Rusty Russell
  
From: Rusty Russell @ 2018-12-12 23:49 UTC (permalink / raw)
  To: Johnson Lau, bitcoin-dev

Johnson Lau <jl2012@xbt•hk> writes:
>> On 12 Dec 2018, at 5:42 PM, Rusty Russell via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
>> 
>> Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
>>> Here is a combined proposal:
>>> * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
>>> and SIGHASH_SCRIPTMASK.
>>> * A new opcode OP_MASK is added, which acts as a NOP during execution.
>>> * The sighash is computed like in BIP143, but:
>>>  * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
>>> the subsequent opcode/push is removed.
>> 
>> Having the SIGHASH_SCRIPTMASK flag is redundant AFAICT: why not always
>> perform mask-removal for signing?
>
> Because a hardware wallet may want to know what exact script it is signing?

OK, removing OP_MASKs unconditionally would introduce a hole without
some explicit flag to say they've been removed (the "real script" could
be something different with OP_MASKs).  We could have the signature
commit to the outputscript, but that's a bit meh.

> Masked script has reduced security, but this is a tradeoff with
> functionality (e.g. eltoo can’t work without masking part of the
> script). So when you don’t need that extra functionality, you go back
> to better security
>
> However, I’m not sure if there is any useful NOINPUT case with unmasked script.

This is *not* true of Eltoo; the script itself need not change for the
rebinding (Christian, did something change?).

So, can we find an example where OP_MASK is useful?

>> If you're signing arbitrary scripts, you're surely in trouble already?
>> 
>> And I am struggling to understand the role of scriptmask in a taproot
>> world, where the alternate script is both hidden and general?
>
> It makes sure that your signature is applicable to a specific script branch, not others (assuming you use the same pubkey in many branches, which is avoidable)

If I'm using SIGHASH_NOINPUT, I'm already required to take care with key
reuse.

Without a concrete taproot proposal it's hard to make assertions, but
if the signature flags that it's using the taproot script, it's
no less safe, and more general AFAICT.

Thanks!
Rusty.


 permalink raw reply	[|nested]
2018-12-11 22:50       ` Russell O'Connor
  2018-12-12 19:53         ` Johnson Lau

  2018-12-13 16:21           ` Russell O'Connor
       [not found]         ` <CAAS2fgRma+Pw-rHJSOKRVBqoxqJ3AxHO9d696fWoa-sb17JEOQ@mail.gmail.com>
  
From: Anthony Towns @ 2018-12-13  0:05 UTC (permalink / raw)
  To: Russell O'Connor, Bitcoin Protocol Discussion

On Tue, Dec 11, 2018 at 05:50:24PM -0500, Russell O'Connor via bitcoin-dev wrote:
> On Sun, Dec 9, 2018 at 2:13 PM Johnson Lau <jl2012@xbt•hk> wrote:
>     The current proposal is that a 64-byte signature will be used for the
>     default “signing all” sighash, and 65-byte for other sighash types. The
>     space saved will allow a few more txs in a block, so I think it worths
>     doing. However, this also makes witness weight estimation more difficult in
>     multisig cases.

This seems strange to me -- why wouldn't you just assume every signature
is 65 witness bytes, and just be grateful for the prioritisation benefit
if someone chooses a shorter signature? Your error margin is just 0.25
vbytes per signature.

> I tend to think in opposite terms. Is there a proof that any script can be
> transformed into an equivalent one that avoids witness weight malleability?

An alternative generalisation: is there a proof that all valid witnesses
will have a weight within some small range?

> Moreover, even if witness weight malleability is entirely avoidable, it always
> seems to come at a cost.  Taking as an example libwally's proposed "
> csv_2of3_then_2" Script, it begins with "OP_DEPTH OP_1SUB OP_1SUB"

(DEPTH 2 NUMNOTEQUAL seems like it would have been more obvious...)

Cheers,
aj



 permalink raw reply	[|nested]
2018-12-12  9:42 ` Rusty Russell
  2018-12-12 20:00   ` Johnson Lau

  
From: Anthony Towns @ 2018-12-13  0:24 UTC (permalink / raw)
  To: Rusty Russell, Bitcoin Protocol Discussion

On Wed, Dec 12, 2018 at 08:12:10PM +1030, Rusty Russell via bitcoin-dev wrote:
> Pieter Wuille via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
> > Here is a combined proposal:
> > * Three new sighash flags are added: SIGHASH_NOINPUT, SIGHASH_NOFEE,
> > and SIGHASH_SCRIPTMASK.
> > * A new opcode OP_MASK is added, which acts as a NOP during execution.
> > * The sighash is computed like in BIP143, but:
> >   * If SIGHASH_SCRIPTMASK is present, for every OP_MASK in scriptCode
> > the subsequent opcode/push is removed.
> I'm asking on-list because I'm sure I'm not the only confused one.
> Having the SIGHASH_SCRIPTMASK flag is redundant AFAICT: why not always
> perform mask-removal for signing?

The way I'm thinking about it is there's four amounts of knowledge you
could have about the input you're spending at the time you generate a
signature:

 ALL: you know everything about every input for this tx

 SINGLE: you know everything about the input you're signing for, but
   not necessarily the others

 SCRIPTPUBKEY: you know the exact scriptPubKey you're trying to satisfy, but
   don't know the txid

 SCRIPTMASK: you don't know the txid, don't know the scriptPubKey, don't
   know the other taproot branches, and maybe don't even know the masked
   out terms in the script -- but you do know the structure of the
   script, and the non-masked terms

There's no value to masking in any but the final case -- the txid and
scriptPubKey commit to the full scriptcode already, so also signing the
scriptcode is just belt-and-suspenders protection.

(It might be that the "SCRIPTPUBKEY" option isn't very useful in
practice; maybe you'll always either know the txid, or need to mask
something?)

> And I am struggling to understand the role of scriptmask in a taproot
> world, where the alternate script is both hidden and general?

In a taproot world, your scriptPubKey is a point P=Q+H(Q,S)*G, where S
is a merkle root of possibly many scripts, and is spendable either by:

  sig(P)
  Q, path(S,script), script, witness(script)

SCRIPTMASK lets you prepare a signature for one particular script in
advance, even before you've decided what the other scripts are (and even
what the base point Q is), let alone built an actual transaction.

At least, that's my current understanding; and I think it makes sense...

Cheers,
aj


 permalink raw reply	[|nested]
2018-12-12 23:49     ` Rusty Russell

  2018-12-14  9:30         ` Anthony Towns
  
From: Rusty Russell @ 2018-12-13  0:37 UTC (permalink / raw)
  To: Johnson Lau, bitcoin-dev

Rusty Russell <rusty@rustcorp•com.au> writes:
>> However, I’m not sure if there is any useful NOINPUT case with unmasked script.
>
> This is *not* true of Eltoo; the script itself need not change for the
> rebinding (Christian, did something change?).

This is wrong, sorry.  I re-checked the paper, and the constant for the
timelock comparison changes on each new update.

(The alternative was a new opcode like OP_TIMELOCKGREATERVERIFY which
required remembering the nLocktime for the UTXO).

So now my opinion is closer to yours: what's the use for NOINPUT &&
!NOMASK?

And is it worthwhile doing the mask complexity, rather than just
removing the commitment to script with NOINPUT?  It *feels* safer to
restrict what scripts we can sign, but is it?

Note that NOINPUT is only useful when you can't just re-sign the tx, and
you need to be able to create a new tx even if this input is spent once
(an attacker can do this with SIGHASH_MASK or not!).  ie. any other
inputs need to be signed NOINPUT or this one
SIGHASH_SINGLE|ANYONECANPAY.

You already need both key-reuse and amount-reuse to be exploited.
SIGHASH_MASK only prevents you from reusing this input for a "normal"
output; if you used this key for multiple scripts of the same form,
you're vulnerable[1].  Which, given the lightning software will be using
the One True Script, is more likely that your normal wallet using the
same keys.

So I don't think it's worth it.  SIGHASH_NOINPUT is simply dangerous
with key-reuse, and Don't Do That.

Cheers,
Rusty.
[1] Attacker can basically clone channel state to another channel.


 permalink raw reply	[|nested]
2018-12-13  0:05         ` Anthony Towns

  2018-12-14  0:47             ` Anthony Towns
  
From: Russell O'Connor @ 2018-12-13 16:21 UTC (permalink / raw)
  To: Anthony Towns;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 2031 bytes --]

On Wed, Dec 12, 2018 at 7:06 PM Anthony Towns <aj@erisian•com.au> wrote:

> On Tue, Dec 11, 2018 at 05:50:24PM -0500, Russell O'Connor via bitcoin-dev
> wrote:
> > On Sun, Dec 9, 2018 at 2:13 PM Johnson Lau <jl2012@xbt•hk> wrote:
> >     The current proposal is that a 64-byte signature will be used for the
> >     default “signing all” sighash, and 65-byte for other sighash types.
> The
> >     space saved will allow a few more txs in a block, so I think it
> worths
> >     doing. However, this also makes witness weight estimation more
> difficult in
> >     multisig cases.
>
> This seems strange to me -- why wouldn't you just assume every signature
> is 65 witness bytes, and just be grateful for the prioritisation benefit
> if someone chooses a shorter signature? Your error margin is just 0.25
> vbytes per signature.
>

The issue is that the proposal is to sign the actual weight, rather than
sign an upper bound on the weight.
The problem with signing an upper bound, is that you need to specify that
upper bound someplace in the transaction, and we are out of sneaky places
to stash that data.
Signing the actual weight is easy because the total weight is implicit, but
now you need to know the total weight before signing.


> > I tend to think in opposite terms. Is there a proof that any script can
> be
> > transformed into an equivalent one that avoids witness weight
> malleability?
>
> An alternative generalisation: is there a proof that all valid witnesses
> will have a weight within some small range?
>
> > Moreover, even if witness weight malleability is entirely avoidable, it
> always
> > seems to come at a cost.  Taking as an example libwally's proposed "
> > csv_2of3_then_2" Script, it begins with "OP_DEPTH OP_1SUB OP_1SUB"
>
> (DEPTH 2 NUMNOTEQUAL seems like it would have been more obvious...)
>
> I think the 1SUB idea was derived from the csv_2of2_then_1 Script where
DEPTH 1SUB is shorter than DEPTH 1 NUMNOTEQUAL.


> Cheers,
> aj
>
>

[-- Attachment #2: Type: text/html, Size: 2768 bytes --]

 permalink raw reply	[|nested]
[not found]         ` <CAAS2fgRma+Pw-rHJSOKRVBqoxqJ3AxHO9d696fWoa-sb17JEOQ@mail.gmail.com>

  
From: Russell O'Connor @ 2018-12-13 16:34 UTC (permalink / raw)
  To: Gregory Maxwell;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 2245 bytes --]

On Wed, Dec 12, 2018 at 12:26 PM Gregory Maxwell <gmaxwell@gmail•com> wrote:

> On Wed, Dec 12, 2018 at 5:15 PM Russell O'Connor via bitcoin-dev
> <bitcoin-dev@lists•linuxfoundation.org> wrote:
> > I tend to think in opposite terms. Is there a proof that any script can
> be transformed into an equivalent one that avoids witness weight
> malleability?   But I admit there is a trade off:  If we don't allow for
> signature covers weight, and we do need it, it will be too late to add.  On
> the other hand if we add signature covers weight, but it turns out that no
> Script ever needs to use it, then we've added that software complexity for
> no gain.  However, I think the software complexity is relatively low,
> making it worthwhile.
> >
> > Moreover, even if witness weight malleability is entirely avoidable, it
> always seems to come at a cost.  Taking as an example libwally's proposed
> "csv_2of3_then_2"
>
> I'm largely in agreement with you-- but my difficulty in arguing for
> signing the weight is that it seemed to me that it was only easy to
> sign an upper bound because some witnesses are variable size... and
> signing an upper bound means more signalling overhead... offsetting
> the space gains for demalleating.
>

In multi-party protocols, the last person to sign knows what the total
weight is going to be (now that we have fixed sized signatures) and at
least they have the ability to sign it.  They are probably motivated to
sign the weight as long as they are interested in the success of the
transaction.  I suppose there could be asynchronous protocols where there
isn't a last person to sign, but that seems a bit weird.  Greg, you are
probably more familiar with examples of multi-party protocols than I am.

OTOH maybe the last person to sign isn't interested in the success of the
transaction and wants to cause grief by bloating the transaction and
signing the bloated weight.  I guess in such protocols, you'll have to keep
the anti-malleablity Script Code.

I totally get the idea that signing weight has a lot of issues in many
scenarios.  But I still feel than on the whole it is better to make the
option available than to be forced to rely on anti-malleability Script Code
or non-consensus relay policy.

[-- Attachment #2: Type: text/html, Size: 2726 bytes --]

 permalink raw reply	[|nested]
2018-12-12 19:53         ` Johnson Lau

  
From: Russell O'Connor @ 2018-12-13 16:50 UTC (permalink / raw)
  To: Johnson Lau;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 2693 bytes --]

On Wed, Dec 12, 2018 at 2:53 PM Johnson Lau <jl2012@xbt•hk> wrote:

>
> I think the root cause of witness weight malleability is some opcodes
> accept variable size input (without affecting the output), and that input
> is provided by the puzzle solver. Going through the opcode list, I think
> such opcodes include IF, NOTIF, VERIFY, DROP, 2DROP, NIP, DEPTH, and all
> arithmetic opcode that accepts CScriptNum (including CHECKMULTISIG)
>
> VERIFY, DROP, 2DROP, NIP are not real problem, since they should not be
> the first opcode to interact with data directly provided by the puzzle
> solver.
>
> CHECKMULTISIG is fixed by BIP147. For the key number and sig number, they
> should be part of the script, so not malleable.
>
> DEPTH is a problem only if its inputs are not later examined by other
> opcodes. Again, this is pointless.
>
> The liberally example should be protected by the MINIMAL_IF policy, which
> requires the input of OP_IF be minimal. As you note, OP_IF could be
> replaced by taproot in many cases
>
> Non-minimal CScriptNum is also banned as BIP62 policy.
>
> For the purpose of preventing malicious third party witness bloating, all
> we need is the miners to enforce the policy. There is no reason for miners
> to accept size malleated txs, as that will reduce the usable block space.
> If they hate a tx, they would simply drop it, instead of wasting the block
> space.
>

I don't know if it such a clear cut case for miner's policy.  A miner is
passed a malleated tx.  They know that there is probably a non-malleated
variant floating around out there somewhere, and they would rather have
it.  But right now they don't, and they probably not going to try to
unmalleate it themselves.  So, why not stick it into their mempool?  If it
eventually makes it into one of their blocks, then it will because it has
the best fee rate available, and to reject it outright is harmful to their
bottom line.  If they find the non-malleated variant later, great, they can
replace it and gain a higher-fee rate tx.  Of course, such a policy opens
them up to a Denial of Service attack.

So what do they do?  Do they accept malleated tx's and implement an RBF
policy that requires sufficient fee rate increases?  Do they reject
malleated txs outright to avoid falling in this trap in the first place as
you suggest?  I don't know, but I don't think things are as clear cut as
you present.


That aside, your list of weight malleable opcodes is shorter than I
imagined and I'm grateful you've compiled it.  Perhaps the best solution is
to make MINIMAL_IF and minimal CScriptNum consensus enforced in the next
version of Script and all but eliminate weight malleability in practice?

[-- Attachment #2: Type: text/html, Size: 3242 bytes --]

 permalink raw reply	[|nested]
2018-12-13 16:21           ` Russell O'Connor

  
From: Anthony Towns @ 2018-12-14  0:47 UTC (permalink / raw)
  To: Russell O'Connor;  Bitcoin Protocol Discussion

On Thu, Dec 13, 2018 at 11:21:10AM -0500, Russell O'Connor wrote:
> On Wed, Dec 12, 2018 at 7:06 PM Anthony Towns <aj@erisian•com.au> wrote:
>     On Tue, Dec 11, 2018 at 05:50:24PM -0500, Russell O'Connor via bitcoin-dev
>     wrote:
>     > On Sun, Dec 9, 2018 at 2:13 PM Johnson Lau <jl2012@xbt•hk> wrote:
>     >     The current proposal is that a 64-byte signature will be used for the
>     >     default “signing all” sighash, and 65-byte for other sighash types.
>     The
>     >     space saved will allow a few more txs in a block, so I think it
>     worths
>     >     doing. However, this also makes witness weight estimation more
>     difficult in
>     >     multisig cases.
>     This seems strange to me -- why wouldn't you just assume every signature
>     is 65 witness bytes, and just be grateful for the prioritisation benefit
>     if someone chooses a shorter signature? Your error margin is just 0.25
>     vbytes per signature.
> The issue is that the proposal is to sign the actual weight, rather than sign
> an upper bound on the weight.

Sorry, I elided some of my reasoning. Suppose witness data wasn't
malleable; in that case any valid witness for a particular script would
have the exact same weight, and it would be good enough to just sign
the script, because that also commits to the witness weight. (And if
you're doing SIGHASH_ALL, you're committing to the exact transaction
weight too)

I think the benefit of signing the weight is mostly that it also commits
to the feerate and hence transaction priority: you know how much you're
paying in fees when you sign, but the reason you're paying any fees is
to get a particular priority for your transaction, so if that can change
from under you because the tx weight changes, you're being ripped off
(either because you get less priority than you were paying for, or
because you get more than you wanted and would have paid less if you'd
known).

But if, just from looking at the script, you can be sure the witness
weight will be between "w" and "w + 0.8%" and your fee is "f", you
know your feerate (and hence priority) is between "f/w - 0.8%" and
"f/w". If the "0.8%" is small enough, that's just a rounding error and
you probably have more uncertainty in your feerate estimations anyway. So
I think at that point it's reasonable to target the lower bound feerate
("f/w - 0.8%"), because your only potential loss is that you get a higher
feerate and would have saved "0.8%" on f if you'd been able to be 100%
sure of that.

> The problem with signing an upper bound, is that you need to specify that upper
> bound someplace in the transaction, and we are out of sneaky places to stash
> that data.
> Signing the actual weight is easy because the total weight is implicit, but now
> you need to know the total weight before signing.

The cases where the tx is malleable by someone else, and you know what
the weight should be in advance, and you can't take the final tx once it
hits your mempool and fix the weight to what it should be and
rebroadcast, seem limited to me?

Being able to commit to a minimum feerate seems like it would be more
generally useful: it would apply for ANYONECANPAY crowd-funding type
txes as well; "here's my input, and I'm paying 3 sat/vb feerate, but only
if everyone else does too!". You could do that, I think, with a rule
along the lines of:

  (a) take the actual tx feerate, f*4000/w
  (b) round it down to the nearest exponent of 1.05 sat/kvbyte,
      so 1.3 sat/vbyte becomes 1240.62 (1.05**146 < 1.05**147=1302)
  (c) if the signature doesn't have an extra byte, then it should
      commit to that exponent (146)
  (d) if the signature does have an extra byte, b, then b<=146 and
      the signature should commit to 146-(1+b)

That way if you sign something that says "minimum fee rate of 0.001 sat
per vbyte", you commit to an exponent of 0, and someone else can raise the
feerate anywhere up to 265.7 sat/vb just by tweaking your signature to
indicate how much they've raised the feerate. Likewise you could commit
to some other exponent, and anyone else could adjust your signature to
remain valid for a tx with a feerate of up to 265,742 times greater than
what you expected, but never more than 5% less than what you expected.

This seems too complicated to do any time soon; and maybe more
complicated than will ever be worthwhile, though.

Cheers,
aj



 permalink raw reply	[|nested]
2018-12-13  0:37       ` Rusty Russell

  2018-12-14 13:55           ` Johnson Lau
  2018-12-16  6:55           ` Rusty Russell
  
From: Anthony Towns @ 2018-12-14  9:30 UTC (permalink / raw)
  To: bitcoin-dev

On Thu, Dec 13, 2018 at 11:07:28AM +1030, Rusty Russell via bitcoin-dev wrote:
> And is it worthwhile doing the mask complexity, rather than just
> removing the commitment to script with NOINPUT?  It *feels* safer to
> restrict what scripts we can sign, but is it?

If it's not safer in practice, we've spent a little extra complexity
committing to a subset of the script in each signature to no gain. If
it is safer in practice, we've prevented people from losing funds. I'm
all for less complexity, but not for that tradeoff.

Also, saying "I can't see how to break this, so it's probably good
enough, even if other people have a bad feeling about it" is a crypto
anti-pattern, isn't it?

I don't see how you could feasibly commit to more information than script
masking does for use cases where you want to be able to spend different
scripts with the same signature [0]. If that's possible, I'd probably
be for it.

At the same time, script masking does seem feasible, both for
lightning/eltoo, and even for possibly complex variations of scripts. So
committing to less doesn't seem wise.

> You already need both key-reuse and amount-reuse to be exploited.
> SIGHASH_MASK only prevents you from reusing this input for a "normal"
> output; if you used this key for multiple scripts of the same form,
> you're vulnerable[1].

For example, script masking seems general enough to prevent footguns
even if (for some reason) key and value reuse across eltoo channels
were a requirement, rather than prohibited: you'd make the script be
"<eltoo-channel-id> MASK <statenum> CLTV 2DROP <a+b> CHECKSIG", and your
signature will only apply to that channel, even if another channel has
the same capacity and uses the same keys, a and b.

> So I don't think it's worth it.  SIGHASH_NOINPUT is simply dangerous
> with key-reuse, and Don't Do That.

For my money, "NOINPUT" commits to dangerously little context, and
doesn't really feel safe to include as a primitive -- as evidenced by
the suggestion to add "_UNSAFE" or similar to its name. Personally, I'm
willing to accept a bit of risk, so that feeling doesn't make me strongly
against the idea; but it also makes it hard for me to want to support
adding it. To me, committing to a masked script is a huge improvement.

Heck, if it also makes it easier to do something safer, that's also
probably a win...

Cheers,
aj

[0] You could, perhaps, commit to knowing the private keys for all the
    *outputs* you're spending to, as well as the inputs, which comes
    close to saying "I know this is a scary NOINPUT transaction, but
    we're paying to ourselves, so it will all be okay".


 permalink raw reply	[|nested]
2018-12-14  9:30         ` Anthony Towns

  2018-12-17  3:10             ` Rusty Russell
  2018-12-16  6:55           ` Rusty Russell
  
From: Johnson Lau @ 2018-12-14 13:55 UTC (permalink / raw)
  To: Anthony Towns, bitcoin-dev

I don’t think this has been mentioned: without signing the script or masked script, OP_CODESEPARATOR becomes unusable or insecure with NOINPUT.

In the new sighash proposal, we will sign the hash of the full script (or masked script), without any truncation. To make OP_CODESEPARATOR works like before, we will commit to the position of the last executed OP_CODESEPARATOR. If NOINPUT doesn’t commit to the masked script, it will just blindly committing to a random OP_CODESEPARATOR position, which a wallet couldn’t know what codes are actually being executed.

> On 14 Dec 2018, at 5:30 PM, Anthony Towns via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> On Thu, Dec 13, 2018 at 11:07:28AM +1030, Rusty Russell via bitcoin-dev wrote:
>> And is it worthwhile doing the mask complexity, rather than just
>> removing the commitment to script with NOINPUT?  It *feels* safer to
>> restrict what scripts we can sign, but is it?
> 
> If it's not safer in practice, we've spent a little extra complexity
> committing to a subset of the script in each signature to no gain. If
> it is safer in practice, we've prevented people from losing funds. I'm
> all for less complexity, but not for that tradeoff.
> 
> Also, saying "I can't see how to break this, so it's probably good
> enough, even if other people have a bad feeling about it" is a crypto
> anti-pattern, isn't it?
> 
> I don't see how you could feasibly commit to more information than script
> masking does for use cases where you want to be able to spend different
> scripts with the same signature [0]. If that's possible, I'd probably
> be for it.
> 
> At the same time, script masking does seem feasible, both for
> lightning/eltoo, and even for possibly complex variations of scripts. So
> committing to less doesn't seem wise.
> 
>> You already need both key-reuse and amount-reuse to be exploited.
>> SIGHASH_MASK only prevents you from reusing this input for a "normal"
>> output; if you used this key for multiple scripts of the same form,
>> you're vulnerable[1].
> 
> For example, script masking seems general enough to prevent footguns
> even if (for some reason) key and value reuse across eltoo channels
> were a requirement, rather than prohibited: you'd make the script be
> "<eltoo-channel-id> MASK <statenum> CLTV 2DROP <a+b> CHECKSIG", and your
> signature will only apply to that channel, even if another channel has
> the same capacity and uses the same keys, a and b.
> 
>> So I don't think it's worth it.  SIGHASH_NOINPUT is simply dangerous
>> with key-reuse, and Don't Do That.
> 
> For my money, "NOINPUT" commits to dangerously little context, and
> doesn't really feel safe to include as a primitive -- as evidenced by
> the suggestion to add "_UNSAFE" or similar to its name. Personally, I'm
> willing to accept a bit of risk, so that feeling doesn't make me strongly
> against the idea; but it also makes it hard for me to want to support
> adding it. To me, committing to a masked script is a huge improvement.
> 
> Heck, if it also makes it easier to do something safer, that's also
> probably a win...
> 
> Cheers,
> aj
> 
> [0] You could, perhaps, commit to knowing the private keys for all the
>    *outputs* you're spending to, as well as the inputs, which comes
>    close to saying "I know this is a scary NOINPUT transaction, but
>    we're paying to ourselves, so it will all be okay".
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev




 permalink raw reply	[|nested]
2018-12-14  9:30         ` Anthony Towns
  2018-12-14 13:55           ` Johnson Lau

  2018-12-17 19:08             ` Johnson Lau
  
From: Rusty Russell @ 2018-12-16  6:55 UTC (permalink / raw)
  To: Anthony Towns, Bitcoin Protocol Discussion, bitcoin-dev

Anthony Towns via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
> On Thu, Dec 13, 2018 at 11:07:28AM +1030, Rusty Russell via bitcoin-dev wrote:
>> And is it worthwhile doing the mask complexity, rather than just
>> removing the commitment to script with NOINPUT?  It *feels* safer to
>> restrict what scripts we can sign, but is it?
>
> If it's not safer in practice, we've spent a little extra complexity
> committing to a subset of the script in each signature to no gain. If
> it is safer in practice, we've prevented people from losing funds. I'm
> all for less complexity, but not for that tradeoff.

There are many complexities we could add, each of which would prevent
loss of funds in some theoretical case.

From practical experience; reuse of private keys between lightning and
other things is not how people will lose funds[1].

It *is* however non-trivially more complicated for wallets; they
currently have a set of script templates which they will sign (ie. no
OP_CODESEPARATOR) and I implemented BIP 143 with only the simplest of
naive code[2].  In particular, there is no code to parse scripts.

Bitcoind developers are not in a good position to assess complexity
here.  They have to implement *everything*, so each increment seems
minor.  In addition, none of these new script versions will ever make
bitcoind simpler, since they have to support all prior ones.  Wallets,
however, do not have to.

I also think that minimal complexity for (future) wallets is an
underappreciated feature: the state of wallets in bitcoin is poor[3]
so simplicity should be a key goal.

Respectfully,
Rusty.

[1] Reusing your revocation base point across two channels will lose
    funds in a much more trivial way, as will reusing payment hashes
    across invoices.
[2] In fact, I added SIGHASH_ANYONECANPAY and SIGHASH_SINGLE recently
    for Segwit and it worked first time!  Kudos to BIP143's authors for
    such a clear guide.
[3] Bitcoind's wallet can't restore from seed; this neatly demonstrates
    how hard the wallet problem is, but there are many others.












code, as modern wallets currently don't have to parse the scripts they
sign.







I'm telling you that this is not how people are losing funds.



>
> Also, saying "I can't see how to break this, so it's probably good
> enough, even if other people have a bad feeling about it" is a crypto
> anti-pattern, isn't it?
>
> I don't see how you could feasibly commit to more information than script
> masking does for use cases where you want to be able to spend different
> scripts with the same signature [0]. If that's possible, I'd probably
> be for it.
>
> At the same time, script masking does seem feasible, both for
> lightning/eltoo, and even for possibly complex variations of scripts. So
> committing to less doesn't seem wise.
>
>> You already need both key-reuse and amount-reuse to be exploited.
>> SIGHASH_MASK only prevents you from reusing this input for a "normal"
>> output; if you used this key for multiple scripts of the same form,
>> you're vulnerable[1].
>
> For example, script masking seems general enough to prevent footguns
> even if (for some reason) key and value reuse across eltoo channels
> were a requirement, rather than prohibited: you'd make the script be
> "<eltoo-channel-id> MASK <statenum> CLTV 2DROP <a+b> CHECKSIG", and your
> signature will only apply to that channel, even if another channel has
> the same capacity and uses the same keys, a and b.
>
>> So I don't think it's worth it.  SIGHASH_NOINPUT is simply dangerous
>> with key-reuse, and Don't Do That.
>
> For my money, "NOINPUT" commits to dangerously little context, and
> doesn't really feel safe to include as a primitive -- as evidenced by
> the suggestion to add "_UNSAFE" or similar to its name. Personally, I'm
> willing to accept a bit of risk, so that feeling doesn't make me strongly
> against the idea; but it also makes it hard for me to want to support
> adding it. To me, committing to a masked script is a huge improvement.
>
> Heck, if it also makes it easier to do something safer, that's also
> probably a win...
>
> Cheers,
> aj
>
> [0] You could, perhaps, commit to knowing the private keys for all the
>     *outputs* you're spending to, as well as the inputs, which comes
>     close to saying "I know this is a scary NOINPUT transaction, but
>     we're paying to ourselves, so it will all be okay".
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev


 permalink raw reply	[|nested]
2018-12-14 13:55           ` Johnson Lau

  2018-12-20 19:34               ` Johnson Lau
  
From: Rusty Russell @ 2018-12-17  3:10 UTC (permalink / raw)
  To: Johnson Lau, Anthony Towns, bitcoin-dev

Johnson Lau <jl2012@xbt•hk> writes:
> I don’t think this has been mentioned: without signing the script or masked script, OP_CODESEPARATOR becomes unusable or insecure with NOINPUT.
>
> In the new sighash proposal, we will sign the hash of the full script (or masked script), without any truncation. To make OP_CODESEPARATOR works like before, we will commit to the position of the last executed OP_CODESEPARATOR. If NOINPUT doesn’t commit to the masked script, it will just blindly committing to a random OP_CODESEPARATOR position, which a wallet couldn’t know what codes are actually being executed.

My anti-complexity argument leads me to ask why we'd support
OP_CODESEPARATOR at all?  Though my argument is weaker here: no wallet
need support it.

But I don't see how OP_CODESEPARATOR changes anything here, wrt NOINPUT?
Remember, anyone can create an output which can be spent by any NOINPUT,
whether we go for OP_MASK or simply not commiting to the input script.

Confused,
Rusty.


 permalink raw reply	[|nested]
2018-12-16  6:55           ` Rusty Russell

  2018-12-18  4:22               ` Peter Todd
  2018-12-19  0:39               ` Rusty Russell
  
From: Johnson Lau @ 2018-12-17 19:08 UTC (permalink / raw)
  To: Rusty Russell, bitcoin-dev



> On 16 Dec 2018, at 2:55 PM, Rusty Russell via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
> 
> Anthony Towns via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
>> On Thu, Dec 13, 2018 at 11:07:28AM +1030, Rusty Russell via bitcoin-dev wrote:
>>> And is it worthwhile doing the mask complexity, rather than just
>>> removing the commitment to script with NOINPUT?  It *feels* safer to
>>> restrict what scripts we can sign, but is it?
>> 
>> If it's not safer in practice, we've spent a little extra complexity
>> committing to a subset of the script in each signature to no gain. If
>> it is safer in practice, we've prevented people from losing funds. I'm
>> all for less complexity, but not for that tradeoff.
> 
> There are many complexities we could add, each of which would prevent
> loss of funds in some theoretical case.

Every security measures are overkill, until someone get burnt. If these security measures are really effective, no one will get burnt. The inevitable conclusion is: every effective security measures are overkill.

> 
> From practical experience; reuse of private keys between lightning and
> other things is not how people will lose funds[1].

Assuming an user holds a private key exclusively and securely, currently there are only 2 ways to lose funds by private key reuse: 1. reusing the same signature nonce; 2. signing the hash “one”, for the SIGHASH_SINGLE consensus bug.

People lost money for the first reason. Since this is a feature of the signature schemes we use, unavoidably that will happen again from time to time. The second one has been fixed in segwit (though incompletely), and could be completely fixed with a simple softfork.

Overall speaking, while private key reuse hurts fungibility and privacy, it is not terribly insecure, as long as you use rfc6979 and are not foolish enough to sign hash “one”. This actually thanks to the fact that signatures always committed to the previous txid. It makes sure that a signature is never valid for more than one UTXO. Unfortunately, the guarantee of non-replayability incentified the practice of key-reuse, since the day-one of bitcoin. While NOINPUT fundamentally changes this security assumption, it won’t change this long-established culture of key reuse.

So you argument seems just begging the question. Without NOINPUT, it is just impossible to lose money by key reuse, and this is exactly the topic we are debating.


> 
> It *is* however non-trivially more complicated for wallets; they
> currently have a set of script templates which they will sign (ie. no
> OP_CODESEPARATOR) and I implemented BIP 143 with only the simplest of
> naive code[2].  In particular, there is no code to parse scripts.

Sorry that I’m not familiar with the implementation details of your wallet. But as you don’t have code to parse scripts, I assume your wallet can’t handle OP_CODESEPARATOR? However, this is exactly what you should do: only implement what you actually need, and ignore those unrelated details.

Also, trying to faithfully and completely reproduce the consensus code in a wallet (even if you don’t need that at all) could be extremely dangerous. Such wallet might be tricked, for example, to sign the hash “one” and get all money stolen (I was told someone really did that, but I don’t know the details)

If you didn’t implement OP_CODESEPARATOR because you didn’t use it, there is no reason for you to fully implement OP_MASKEDPUSH nor script parsing. In existing signature schemes (e.g. BIP143), signatures always commit to the script being executed (the “scriptCode”). I assume that all wallets would re-construct the scriptCode at signing time, based on the limited set of script templates they support. If a wallet had a function called GetScriptCodeForMultiSig() for this purpose, all they need now is a GetMaskedScriptCodeForMultiSig() that returns the masked template, or a new option in the existing GetScriptCodeForMultiSig(). It does not need to be something like GetMaskedScript(GetScriptCodeForMultiSig()). After all, only a very small number of script templates really need NOINPUT. A GetMaskedScript() in a wallet is just an overkill (and a vulnerability if mis-implemented) 

> 
> Bitcoind developers are not in a good position to assess complexity
> here.  They have to implement *everything*, so each increment seems
> minor.  In addition, none of these new script versions will ever make
> bitcoind simpler, since they have to support all prior ones.  Wallets,
> however, do not have to.
> 
> I also think that minimal complexity for (future) wallets is an
> underappreciated feature: the state of wallets in bitcoin is poor[3]
> so simplicity should be a key goal.

It is a 3-way tradeoff of security, complexity, and functionality. While not everyone might appreciate this, security seems to always be the dominent factor in bitcoin protocol development. It was the reason why most core contributors were hesitant towards BIP148, despite they all love the functionality of segwit.

It’s also about functionality here: as I mentioned in another reply, OP_CODESEPARATOR couldn’t function properly with NOINPUT but without OP_MASKEDPUSH

This debate happens because NOINPUT introduces the third way to lose fund with key reuse. And once it is deployed, we have to support it forever, and is not something that we could softfork it away.


> 
> Respectfully,
> Rusty.
> 
> [1] Reusing your revocation base point across two channels will lose
>    funds in a much more trivial way, as will reusing payment hashes
>    across invoices.
> [2] In fact, I added SIGHASH_ANYONECANPAY and SIGHASH_SINGLE recently
>    for Segwit and it worked first time!  Kudos to BIP143's authors for
>    such a clear guide.
> [3] Bitcoind's wallet can't restore from seed; this neatly demonstrates
>    how hard the wallet problem is, but there are many others.
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> code, as modern wallets currently don't have to parse the scripts they
> sign.
> 
> 
> 
> 
> 
> 
> 
> I'm telling you that this is not how people are losing funds.
> 
> 
> 
>> 
>> Also, saying "I can't see how to break this, so it's probably good
>> enough, even if other people have a bad feeling about it" is a crypto
>> anti-pattern, isn't it?
>> 
>> I don't see how you could feasibly commit to more information than script
>> masking does for use cases where you want to be able to spend different
>> scripts with the same signature [0]. If that's possible, I'd probably
>> be for it.
>> 
>> At the same time, script masking does seem feasible, both for
>> lightning/eltoo, and even for possibly complex variations of scripts. So
>> committing to less doesn't seem wise.
>> 
>>> You already need both key-reuse and amount-reuse to be exploited.
>>> SIGHASH_MASK only prevents you from reusing this input for a "normal"
>>> output; if you used this key for multiple scripts of the same form,
>>> you're vulnerable[1].
>> 
>> For example, script masking seems general enough to prevent footguns
>> even if (for some reason) key and value reuse across eltoo channels
>> were a requirement, rather than prohibited: you'd make the script be
>> "<eltoo-channel-id> MASK <statenum> CLTV 2DROP <a+b> CHECKSIG", and your
>> signature will only apply to that channel, even if another channel has
>> the same capacity and uses the same keys, a and b.
>> 
>>> So I don't think it's worth it.  SIGHASH_NOINPUT is simply dangerous
>>> with key-reuse, and Don't Do That.
>> 
>> For my money, "NOINPUT" commits to dangerously little context, and
>> doesn't really feel safe to include as a primitive -- as evidenced by
>> the suggestion to add "_UNSAFE" or similar to its name. Personally, I'm
>> willing to accept a bit of risk, so that feeling doesn't make me strongly
>> against the idea; but it also makes it hard for me to want to support
>> adding it. To me, committing to a masked script is a huge improvement.
>> 
>> Heck, if it also makes it easier to do something safer, that's also
>> probably a win...
>> 
>> Cheers,
>> aj
>> 
>> [0] You could, perhaps, commit to knowing the private keys for all the
>>    *outputs* you're spending to, as well as the inputs, which comes
>>    close to saying "I know this is a scary NOINPUT transaction, but
>>    we're paying to ourselves, so it will all be okay".
>> _______________________________________________
>> 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




 permalink raw reply	[|nested]
2018-12-17 19:08             ` Johnson Lau

  2018-12-19  0:39               ` Rusty Russell
  
From: Peter Todd @ 2018-12-18  4:22 UTC (permalink / raw)
  To: Johnson Lau, Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 1248 bytes --]

On Tue, Dec 18, 2018 at 03:08:26AM +0800, Johnson Lau via bitcoin-dev wrote:
> >> If it's not safer in practice, we've spent a little extra complexity
> >> committing to a subset of the script in each signature to no gain. If
> >> it is safer in practice, we've prevented people from losing funds. I'm
> >> all for less complexity, but not for that tradeoff.
> > 
> > There are many complexities we could add, each of which would prevent
> > loss of funds in some theoretical case.
> 
> Every security measures are overkill, until someone get burnt. If these security measures are really effective, no one will get burnt. The inevitable conclusion is: every effective security measures are overkill.

This isn't really a security issue, it's a software reliability issue. And
you're making a trade-off between complexity of the core protocol and
complexity of wallet software.

A core protocol failure has high costs for every single Bitcoin user; a wallet
software failure affects a much smaller number of people. So I'd be inclined to
prioritise core protocol simplicity rather than stamping out one of many, many,
ways that wallet software can screw up and lose money.

-- 
https://petertodd.org 'peter'[:-1]@petertodd.org

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

 permalink raw reply	[|nested]
2018-12-17 19:08             ` Johnson Lau
  2018-12-18  4:22               ` Peter Todd

  2019-02-09  0:39                 ` Pieter Wuille
  
From: Rusty Russell @ 2018-12-19  0:39 UTC (permalink / raw)
  To: Johnson Lau, bitcoin-dev

Johnson Lau <jl2012@xbt•hk> writes:
>> On 16 Dec 2018, at 2:55 PM, Rusty Russell via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:
>> 
>> Anthony Towns via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> writes:
>>> On Thu, Dec 13, 2018 at 11:07:28AM +1030, Rusty Russell via bitcoin-dev wrote:
>>>> And is it worthwhile doing the mask complexity, rather than just
>>>> removing the commitment to script with NOINPUT?  It *feels* safer to
>>>> restrict what scripts we can sign, but is it?
>>> 
>>> If it's not safer in practice, we've spent a little extra complexity
>>> committing to a subset of the script in each signature to no gain. If
>>> it is safer in practice, we've prevented people from losing funds. I'm
>>> all for less complexity, but not for that tradeoff.
>> 
>> There are many complexities we could add, each of which would prevent
>> loss of funds in some theoretical case.
>
> Every security measures are overkill, until someone get burnt. If these security measures are really effective, no one will get burnt. The inevitable conclusion is: every effective security measures are overkill.
>
>> 
>> From practical experience; reuse of private keys between lightning and
>> other things is not how people will lose funds[1].
>
> So you argument seems just begging the question. Without NOINPUT, it is just impossible to lose money by key reuse, and this is exactly the topic we are debating.

I think we're getting confused here.  I'm contributing my thoughts from
the lightning implementer's point of view; there are other important
considerations, but this is my contribution.

In *lightning* there are more ways to lose funds via secret reuse.

Meanwhile, both SIGHASH_NOINPUT and OP_MASK have the reuse-is-dangerous
property; with OP_MASK the danger is limited to reuse-on-the-same-script
(ie. if you use the same key for a non-lightning output and a lightning
output, you're safe with OP_MASK.  However, this is far less likely in
practice).

I state again: OP_MASK doesn't seem to gain *lightning* any significant
security benefit.

> It does not need to be something like GetMaskedScript(GetScriptCodeForMultiSig()). After all, only a very small number of script templates really need NOINPUT. A GetMaskedScript() in a wallet is just an overkill (and a vulnerability if mis-implemented) 

Our current transaction signing code is quite generic (and, if I may say
so, readable and elegant).  We could, of course, special case
GetMaskedScript() for the case we need (the Eltoo examples I've seen
have a single OP_MASK at the front, which makes it trivial).

> It’s also about functionality here: as I mentioned in another reply, OP_CODESEPARATOR couldn’t function properly with NOINPUT but without OP_MASKEDPUSH

The mailing list seems a bit backed up or something; I replied to that
in the hope you can clear my confusion on that one.

> This debate happens because NOINPUT introduces the third way to lose fund with key reuse. And once it is deployed, we have to support it forever, and is not something that we could softfork it away.

A would use the same words to encourage you to create the simplest
possible implementation?

I don't think we disagree on philosophy, just trade-offs.  And that's
OK.

Cheers,
Rusty.


 permalink raw reply	[|nested]
2018-12-17  3:10             ` Rusty Russell

  2018-12-20 23:17                 ` Rusty Russell
  
From: Johnson Lau @ 2018-12-20 19:34 UTC (permalink / raw)
  To: Rusty Russell;  bitcoin-dev

[-- Attachment #1: Type: text/plain, Size: 2791 bytes --]



> On 17 Dec 2018, at 11:10 AM, Rusty Russell <rusty@rustcorp•com.au> wrote:
> 
> Johnson Lau <jl2012@xbt•hk> writes:
>> I don’t think this has been mentioned: without signing the script or masked script, OP_CODESEPARATOR becomes unusable or insecure with NOINPUT.
>> 
>> In the new sighash proposal, we will sign the hash of the full script (or masked script), without any truncation. To make OP_CODESEPARATOR works like before, we will commit to the position of the last executed OP_CODESEPARATOR. If NOINPUT doesn’t commit to the masked script, it will just blindly committing to a random OP_CODESEPARATOR position, which a wallet couldn’t know what codes are actually being executed.
> 
> My anti-complexity argument leads me to ask why we'd support
> OP_CODESEPARATOR at all?  Though my argument is weaker here: no wallet
> need support it.

Because it could make scripts more compact in some cases?

This is an example: https://github.com/bitcoin/bitcoin/pull/11423#issuecomment-333441321 <https://github.com/bitcoin/bitcoin/pull/11423#issuecomment-333441321>

But this is probably not a good example for taproot, as it could be more efficient by making the 2 branches as different script merkle leaves.


> 
> But I don't see how OP_CODESEPARATOR changes anything here, wrt NOINPUT?
> Remember, anyone can create an output which can be spent by any NOINPUT,
> whether we go for OP_MASK or simply not commiting to the input script.
> 

Let me elaborate more. Currently, scriptCode is truncated at the last executed CODESEPARATOR. If we have a very big script with many CODESEPARATORs and CHECKSIGs, there will be a lot of hashing to do.

To fix this problem, it is proposed that the new sighash will always commit to the same H(script), instead of the truncated scriptCode. So we only need to do the H(script) once, even if the script is very big

In the case of NOINPUT with MASKEDSCRIPT, it will commit to the H(masked_script) instead of H(script).

To make CODESEPARATOR works as before, the sighash will also commit to the position of the last executed CODESEPARATOR. So the semantics doesn’t change. For scripts without CODESEPARATOR, the committed value is a constant.

IF NOINPUT does not commit to H(masked_script), technically it could still commit to the position of the last executed CODESEPARATOR. But since the wallet is not aware of the actual content of the script, it has to guess the meaning of such committed positions, like “with the HD key path m/x/y/z, I assume the script template is blah blah blah because I never use this path for another script template, and the meaning of signing the 3rd CODESEPARATOR is blah blah blah”. It still works if the assumptions hold, but sounds quite unreliable to me.

Johnson


[-- Attachment #2: Type: text/html, Size: 3871 bytes --]

 permalink raw reply	[|nested]
2018-12-20 19:34               ` Johnson Lau

  2018-12-21 18:54                   ` Johnson Lau
  
From: Rusty Russell @ 2018-12-20 23:17 UTC (permalink / raw)
  To: Johnson Lau;  bitcoin-dev

Johnson Lau <jl2012@xbt•hk> writes:

>> On 17 Dec 2018, at 11:10 AM, Rusty Russell <rusty@rustcorp•com.au> wrote:
>> My anti-complexity argument leads me to ask why we'd support
>> OP_CODESEPARATOR at all?  Though my argument is weaker here: no wallet
>> need support it.
>
> Because it could make scripts more compact in some cases?
>
> This is an example: https://github.com/bitcoin/bitcoin/pull/11423#issuecomment-333441321 <https://github.com/bitcoin/bitcoin/pull/11423#issuecomment-333441321>
>
> But this is probably not a good example for taproot, as it could be more efficient by making the 2 branches as different script merkle leaves.

Thanks, I hadn't seen this before!  That's also the first time I've seen
SIGHASH_NONE used.

>> But I don't see how OP_CODESEPARATOR changes anything here, wrt NOINPUT?
>> Remember, anyone can create an output which can be spent by any NOINPUT,
>> whether we go for OP_MASK or simply not commiting to the input script.
>> 
>
> Let me elaborate more. Currently, scriptCode is truncated at the last executed CODESEPARATOR. If we have a very big script with many CODESEPARATORs and CHECKSIGs, there will be a lot of hashing to do.
>
> To fix this problem, it is proposed that the new sighash will always commit to the same H(script), instead of the truncated scriptCode. So we only need to do the H(script) once, even if the script is very big

Yes, I read this as proposed, it is clever.  Not sure we'd be
introducing it if OP_CODESEPARATOR didn't already exist, but at least
it's a simplfication.

> In the case of NOINPUT with MASKEDSCRIPT, it will commit to the H(masked_script) instead of H(script).
>
> To make CODESEPARATOR works as before, the sighash will also commit to the position of the last executed CODESEPARATOR. So the semantics doesn’t change. For scripts without CODESEPARATOR, the committed value is a constant.
>
> IF NOINPUT does not commit to H(masked_script), technically it could still commit to the position of the last executed CODESEPARATOR. But since the wallet is not aware of the actual content of the script, it has to guess the meaning of such committed positions, like “with the HD key path m/x/y/z, I assume the script template is blah blah blah because I never use this path for another script template, and the meaning of signing the 3rd CODESEPARATOR is blah blah blah”. It still works if the assumptions hold, but sounds quite unreliable to me.

My question is more fundamental.  If NOINPUT doesn't commit to the input
at all, no script, no code separator, nothing.  I'm struggling to
understand your original comment was "without signing the script or
masked script, OP_CODESEPARATOR becomes unusable or insecure with
NOINPUT."

I mean, non-useful, sure.  Its purpose is to alter signature behavior,
and from the script POV there's no signature with this form of NOINPUT.
But other than the already-established "I reused keys for multiple
outputs" oops, I don't see any new dangers?

Thanks,
Rusty.


 permalink raw reply	[|nested]
2018-12-20 23:17                 ` Rusty Russell

  2018-12-23  4:26                     ` Anthony Towns
  
From: Johnson Lau @ 2018-12-21 18:54 UTC (permalink / raw)
  To: Rusty Russell;  bitcoin-dev



> On 21 Dec 2018, at 7:17 AM, Rusty Russell <rusty@rustcorp•com.au> wrote:
> 
> Johnson Lau <jl2012@xbt•hk> writes:
> 
>>> But I don't see how OP_CODESEPARATOR changes anything here, wrt NOINPUT?
>>> Remember, anyone can create an output which can be spent by any NOINPUT,
>>> whether we go for OP_MASK or simply not commiting to the input script.
>>> 
>> 
>> Let me elaborate more. Currently, scriptCode is truncated at the last executed CODESEPARATOR. If we have a very big script with many CODESEPARATORs and CHECKSIGs, there will be a lot of hashing to do.
>> 
>> To fix this problem, it is proposed that the new sighash will always commit to the same H(script), instead of the truncated scriptCode. So we only need to do the H(script) once, even if the script is very big
> 
> Yes, I read this as proposed, it is clever.  Not sure we'd be
> introducing it if OP_CODESEPARATOR didn't already exist, but at least
> it's a simplfication.
> 
>> In the case of NOINPUT with MASKEDSCRIPT, it will commit to the H(masked_script) instead of H(script).
>> 
>> To make CODESEPARATOR works as before, the sighash will also commit to the position of the last executed CODESEPARATOR. So the semantics doesn’t change. For scripts without CODESEPARATOR, the committed value is a constant.
>> 
>> IF NOINPUT does not commit to H(masked_script), technically it could still commit to the position of the last executed CODESEPARATOR. But since the wallet is not aware of the actual content of the script, it has to guess the meaning of such committed positions, like “with the HD key path m/x/y/z, I assume the script template is blah blah blah because I never use this path for another script template, and the meaning of signing the 3rd CODESEPARATOR is blah blah blah”. It still works if the assumptions hold, but sounds quite unreliable to me.
> 
> My question is more fundamental.  If NOINPUT doesn't commit to the input
> at all, no script, no code separator, nothing.  I'm struggling to
> understand your original comment was "without signing the script or
> masked script, OP_CODESEPARATOR becomes unusable or insecure with
> NOINPUT."
> 
> I mean, non-useful, sure.  Its purpose is to alter signature behavior,
> and from the script POV there's no signature with this form of NOINPUT.
> But other than the already-established "I reused keys for multiple
> outputs" oops, I don't see any new dangers?
> 
> Thanks,
> Rusty.

The question I would like to ask is: is OP_CODESEPARATOR useful under taproot? Generally speaking, CODESEPARATOR is useful only with conditional opcodes (OP_IF etc), and conditional opcodes are mostly replaced by merklized scripts. I am not sure how much usability is left with CODESEPARATOR

If no one needs CODESEPARATOR, we might just disable it, and makes the validation code a bit simpler

If CODESEPARATOR is useful, then we should find a way to make it works with NOINPUT. With H(masked_script) committed, the meaning of the CODESEPARATOR position is very clear. Without H(masked_script), the meaning of the position totally relies on the assumption that “this public key is only used in this script template”.

Ignore CODESEPARATOR and more generally, I agree with you that script masking does not help in the case of address (scriptPubKey) reuse, which is the commonest type of reuse. However, it prevents replayability when the same public key is reused in different scripts


 permalink raw reply	[|nested]
2018-12-21 18:54                   ` Johnson Lau

  2018-12-23 16:33                       ` Johnson Lau
  
From: Anthony Towns @ 2018-12-23  4:26 UTC (permalink / raw)
  To: Johnson Lau;  bitcoin-dev

On Sat, Dec 22, 2018 at 02:54:42AM +0800, Johnson Lau wrote:
> The question I would like to ask is: is OP_CODESEPARATOR useful under taproot? Generally speaking, CODESEPARATOR is useful only with conditional opcodes (OP_IF etc), and conditional opcodes are mostly replaced by merklized scripts. I am not sure how much usability is left with CODESEPARATOR

If you don't have conditionals, then I think committing to the (masked)
script gives you everything you could do with codeseparator.

If you don't commit to the (masked) script, don't have conditionals,
and don't have codeseparator, then I don't think you can make a signature
distinguish which alternative script it's intending to sign; but you can
just give each alternative script in the MAST a slight variation of the
key and that seems good enough.

OTOH, I think for (roughly) the example you gave:

  DEPTH 3 EQUAL
  IF <Bob> CHECKSIGVERIFY HASH160 <H> EQUALVERIFY CODESEP
  ELSE <n> CLTV DROP
  ENDIF
  <Alice> CHECKSIG

then compared to the taproot equivalent:

  P = muSig(Alice,Bob)
  S1 = <Alice1> CHECKSIGVERIFY <Bob> CHECKSIGVERIFY HASH160 <H> EQUAL
  S2 = <Alice2> CHECKSIGVERIFY <n> CLTV

the IF+CODESEP approach is actually cheaper (lighter weight) if you're
mostly (>2/3rds of the time) taking the S1 branch. This is because the
"DEPTH 3 EQUAL IF/ELSE/ENDIF CODESEP <n> CLTV DROP" overhead is less
than the 32B overhead to choose a merkle branch).

(That said, I'm not sure what Alice's signature in the S1 branch actually
achieves in that script; and without that in S1, the taproot approach is
cheaper all the time. Scriptless scripts would be cheaper still)

> If no one needs CODESEPARATOR, we might just disable it, and makes the validation code a bit simpler

Since it only affects the behaviour of the checkdls (checksig) operators,
even if it was disabled, it could be re-enabled fairly easily in a new
script subversion if needed (ie, it could be re-added when upgrading
witness version 1 from script version 0 to 1).

Cheers,
aj



 permalink raw reply	[|nested]
2018-12-23  4:26                     ` Anthony Towns

  2018-12-24 12:01                         ` ZmnSCPxj
  
From: Johnson Lau @ 2018-12-23 16:33 UTC (permalink / raw)
  To: Anthony Towns;  bitcoin-dev



> On 23 Dec 2018, at 12:26 PM, Anthony Towns <aj@erisian•com.au> wrote:
> 
> On Sat, Dec 22, 2018 at 02:54:42AM +0800, Johnson Lau wrote:
>> The question I would like to ask is: is OP_CODESEPARATOR useful under taproot? Generally speaking, CODESEPARATOR is useful only with conditional opcodes (OP_IF etc), and conditional opcodes are mostly replaced by merklized scripts. I am not sure how much usability is left with CODESEPARATOR
> 
> If you don't have conditionals, then I think committing to the (masked)
> script gives you everything you could do with codeseparator.

I don’t think CODESEPARATOR is useful without conditionals. By useful I mean making a script more compact

> 
> If you don't commit to the (masked) script, don't have conditionals,
> and don't have codeseparator, then I don't think you can make a signature
> distinguish which alternative script it's intending to sign; but you can
> just give each alternative script in the MAST a slight variation of the
> key and that seems good enough.

You can and should always use a different in different branch. If this best practice is always followed, committing to masked script is not necessary

> 
> OTOH, I think for (roughly) the example you gave:
> 
>  DEPTH 3 EQUAL
>  IF <Bob> CHECKSIGVERIFY HASH160 <H> EQUALVERIFY CODESEP
>  ELSE <n> CLTV DROP
>  ENDIF
>  <Alice> CHECKSIG
> 
> then compared to the taproot equivalent:
> 
>  P = muSig(Alice,Bob)
>  S1 = <Alice1> CHECKSIGVERIFY <Bob> CHECKSIGVERIFY HASH160 <H> EQUAL
>  S2 = <Alice2> CHECKSIGVERIFY <n> CLTV
> 
> the IF+CODESEP approach is actually cheaper (lighter weight) if you're
> mostly (>2/3rds of the time) taking the S1 branch. This is because the
> "DEPTH 3 EQUAL IF/ELSE/ENDIF CODESEP <n> CLTV DROP" overhead is less
> than the 32B overhead to choose a merkle branch).
> 
> (That said, I'm not sure what Alice's signature in the S1 branch actually
> achieves in that script; and without that in S1, the taproot approach is
> cheaper all the time. Scriptless scripts would be cheaper still)
> 
>> If no one needs CODESEPARATOR, we might just disable it, and makes the validation code a bit simpler
> 
> Since it only affects the behaviour of the checkdls (checksig) operators,
> even if it was disabled, it could be re-enabled fairly easily in a new
> script subversion if needed (ie, it could be re-added when upgrading
> witness version 1 from script version 0 to 1).
> 
> Cheers,
> aj
> 

Yes, I don’t think it needs Alice signature in S1 at all. So the original example doesn’t even need CODESEPARATOR at all. 

Could anyone propose a better use case of CODESEPARATOR?




 permalink raw reply	[|nested]
2018-12-23 16:33                       ` Johnson Lau

  2018-12-24 21:23                           ` Johnson Lau
  
From: ZmnSCPxj @ 2018-12-24 12:01 UTC (permalink / raw)
  To: Johnson Lau, Bitcoin Protocol Discussion

Good morning,

> Could anyone propose a better use case of CODESEPARATOR?

Long ago, aj sent an email on Lightning-dev about use of CODESEPARATOR to impose Scriptless Script even without Schnorr. It involved 3 signatures with different CODESEPARATOR places, and forced R reuse so that the signatures to claim the funds revealed the privkey.

The script shown had all CODESEPARATOR in a single branch.

I cannot claim to understand the script, and am having difficulty digging through the mailinglist

Regards,
ZmnSCPxj


 permalink raw reply	[|nested]
2018-12-24 12:01                         ` ZmnSCPxj

  
From: Johnson Lau @ 2018-12-24 21:23 UTC (permalink / raw)
  To: ZmnSCPxj;  bitcoin-dev

[-- Attachment #1: Type: text/plain, Size: 1933 bytes --]

I find another proposed use of CODESEPARATOR here: https://lists.linuxfoundation.org/pipermail/lightning-dev/2016-March/000455.html <https://lists.linuxfoundation.org/pipermail/lightning-dev/2016-March/000455.html>

<KeyA> OP_CHECKSIG
OP_IF
<KeyB>
OP_ELSE
<Delay> OP_CSV OP_DROP
OP_CODESEPARATOR <KeyA>
OP_ENDIF
OP_CHECKSIG
It is actually 2 scripts:

S1: <KeyA> OP_CHECKSIGVERIFY <KeyB> OP_CHECKSIG
S2: <Delay> OP_CSV OP_DROP <KeyA> OP_CHECKSIG

Under taproot, we could make Q = P + H(P||S2)G, where P = MuSig(KeyA, KeyB)

S1 becomes a direct spending with Q, and there is no need to use OP_IF or CODESEPARATOR in S2 at all.


==================

If it is only to force R reuse, there is no need to use CODESEPARATOR:

Input: <R> <S2>  <S1>  Script: 2DUP EQUAL NOT VERIFY 2 PICK SWAP CAT <key> DUP TOALTSTACK CHECKSIGVERIFY CAT FROMALTSTACK CHECKSIG

But using CODESEPARATOR will save 3 bytes
Input: <S2> <R> <S1>    Script:  OVER SWAP CAT <key> DUP TOALTSTACK CHECKSIGVERIFY CODESEPARATOR SWAP CAT FROMALTSTACK CHECKSIG

However, a much better way would be:

Input: <S> Script: <known R> SWAP CAT <key> CHECKSIG

The discrete log of R could be a shared secret between A and B. If the purpose is to publish the private key to the whole world, R = G could be used.

> On 24 Dec 2018, at 8:01 PM, ZmnSCPxj <ZmnSCPxj@protonmail•com> wrote:
> 
> Good morning,
> 
>> Could anyone propose a better use case of CODESEPARATOR?
> 
> Long ago, aj sent an email on Lightning-dev about use of CODESEPARATOR to impose Scriptless Script even without Schnorr. It involved 3 signatures with different CODESEPARATOR places, and forced R reuse so that the signatures to claim the funds revealed the privkey.
> 
> The script shown had all CODESEPARATOR in a single branch.
> 
> I cannot claim to understand the script, and am having difficulty digging through the mailinglist
> 
> Regards,
> ZmnSCPxj


[-- Attachment #2: Type: text/html, Size: 3774 bytes --]

 permalink raw reply	[|nested]
2018-12-19  0:39               ` Rusty Russell

  
From: Pieter Wuille @ 2019-02-09  0:39 UTC (permalink / raw)
  To: Rusty Russell, Bitcoin Protocol Discussion

On Wed, 19 Dec 2018 at 18:06, Rusty Russell via bitcoin-dev
<bitcoin-dev@lists•linuxfoundation.org> wrote:
>
> Meanwhile, both SIGHASH_NOINPUT and OP_MASK have the reuse-is-dangerous
> property; with OP_MASK the danger is limited to reuse-on-the-same-script
> (ie. if you use the same key for a non-lightning output and a lightning
> output, you're safe with OP_MASK.  However, this is far less likely in
> practice).

Having had some more time to consider this and seeing discussions
about alternatives, I agree. It doesn't seem that OP_MASK protects
against any likely failure modes. I do think that there are realistic
risks around NOINPUT, but output tagging (as suggested in another ML
thread) seems to match those much better than masking does.

Cheers,

-- 
Pieter


 permalink raw reply	[|nested]