Discussion:
BIP sighash_noinput
(too old to reply)
Christian Decker via bitcoin-dev
2018-04-30 16:29:53 UTC
Permalink
Raw Message
Hi all,

I'd like to pick up the discussion from a few months ago, and propose a new
sighash flag, `SIGHASH_NOINPUT`, that removes the commitment to the previous
output. This was previously mentioned on the list by Joseph Poon [1], but was
never formally proposed, so I wrote a proposal [2].

We have long known that `SIGHASH_NOINPUT` would be a great fit for Lightning.
They enable simple watch-towers, i.e., outsource the need to watch the
blockchain for channel closures, and react appropriately if our counterparty
misbehaves. In addition to this we just released the eltoo [3,4] paper which
describes a simplified update mechanism that can be used in Lightning, and other
off-chain contracts, with any number of participants.

By not committing to the previous output being spent by the transaction, we can
rebind an input to point to any outpoint with a matching output script and
value. The binding therefore is no longer explicit through a reference, but
through script compatibility, and the transaction ID reference in the input is a
hint to validators. The sighash flag is meant to enable some off-chain use-cases
and should not be used unless the tradeoffs are well-known. In particular we
suggest using contract specific key-pairs, in order to avoid having any unwanted
rebinding opportunities.

The proposal is very minimalistic, and simple. However, there are a few things
where we'd like to hear the input of the wider community with regards to the
implementation details though. We had some discussions internally on whether to
use a separate opcode or a sighash flag, some feeling that the sighash flag
could lead to some confusion with existing wallets, but given that we have
`SIGHASH_NONE`, and that existing wallets will not sign things with unknown
flags, we decided to go the sighash way. Another thing is that we still commit
to the amount of the outpoint being spent. The rationale behind this is that,
while rebinding to outpoints with the same value maintains the value
relationship between input and output, we will probably not want to bind to
something with a different value and suddenly pay a gigantic fee.

The deployment part of the proposal is left vague on purpose in order not to
collide with any other proposals. It should be possible to introduce it by
bumping the segwit script version and adding the new behavior.

I hope the proposal is well received, and I'm looking forward to discussing
variants and tradeoffs here. I think the applications we proposed so far are
quite interesting, and I'm sure there are many more we can enable with this
change.

Cheers,
Christian

[1] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-February/012460.html
[2] https://github.com/cdecker/bips/blob/noinput/bip-xyz.mediawiki
[3] https://blockstream.com/2018/04/30/eltoo-next-lightning.html
[4] https://blockstream.com/eltoo.pdf
Dario Sneidermanis via bitcoin-dev
2018-04-30 18:25:42 UTC
Permalink
Raw Message
Something like this might also be useful for several use cases related to
RBF. For example:

Alice sends Bob an RBF-activated transaction T1 with the intention of
bumping its fee if necessary. Bob wants to send these funds to Carol, but
cannot wait until T1 confirms, so he crafts a transaction T2 that spends T1
using SIGHASH_NOINPUT, and pays Carol. Carol can now make sure she receives
the money even if Alice fee-bumps T1, as long as the outputs of the
replaced transactions are compatible.

Extra care should be taken to avoid rebinding, maybe by including an extra
input in T2 that doesn't use SIGHASH_NOINPUT.

On Mon, Apr 30, 2018 at 1:29 PM, Christian Decker via bitcoin-dev <
Post by Christian Decker via bitcoin-dev
Hi all,
I'd like to pick up the discussion from a few months ago, and propose a new
sighash flag, `SIGHASH_NOINPUT`, that removes the commitment to the previous
output. This was previously mentioned on the list by Joseph Poon [1], but was
never formally proposed, so I wrote a proposal [2].
We have long known that `SIGHASH_NOINPUT` would be a great fit for Lightning.
They enable simple watch-towers, i.e., outsource the need to watch the
blockchain for channel closures, and react appropriately if our counterparty
misbehaves. In addition to this we just released the eltoo [3,4] paper which
describes a simplified update mechanism that can be used in Lightning, and other
off-chain contracts, with any number of participants.
By not committing to the previous output being spent by the transaction, we can
rebind an input to point to any outpoint with a matching output script and
value. The binding therefore is no longer explicit through a reference, but
through script compatibility, and the transaction ID reference in the input is a
hint to validators. The sighash flag is meant to enable some off-chain use-cases
and should not be used unless the tradeoffs are well-known. In particular we
suggest using contract specific key-pairs, in order to avoid having any unwanted
rebinding opportunities.
The proposal is very minimalistic, and simple. However, there are a few things
where we'd like to hear the input of the wider community with regards to the
implementation details though. We had some discussions internally on whether to
use a separate opcode or a sighash flag, some feeling that the sighash flag
could lead to some confusion with existing wallets, but given that we have
`SIGHASH_NONE`, and that existing wallets will not sign things with unknown
flags, we decided to go the sighash way. Another thing is that we still commit
to the amount of the outpoint being spent. The rationale behind this is that,
while rebinding to outpoints with the same value maintains the value
relationship between input and output, we will probably not want to bind to
something with a different value and suddenly pay a gigantic fee.
The deployment part of the proposal is left vague on purpose in order not to
collide with any other proposals. It should be possible to introduce it by
bumping the segwit script version and adding the new behavior.
I hope the proposal is well received, and I'm looking forward to discussing
variants and tradeoffs here. I think the applications we proposed so far are
quite interesting, and I'm sure there are many more we can enable with this
change.
Cheers,
Christian
[1] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/
2016-February/012460.html
[2] https://github.com/cdecker/bips/blob/noinput/bip-xyz.mediawiki
[3] https://blockstream.com/2018/04/30/eltoo-next-lightning.html
[4] https://blockstream.com/eltoo.pdf
_______________________________________________
bitcoin-dev mailing list
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
Russell O'Connor via bitcoin-dev
2018-05-01 16:58:37 UTC
Permalink
Raw Message
At the risk of bikeshedding, shouldn't NOINPUT also zero out the
hashSequence so that its behaviour is consistent with ANYONECANPAY?

On Mon, Apr 30, 2018 at 12:29 PM, Christian Decker via bitcoin-dev <
Post by Christian Decker via bitcoin-dev
Hi all,
I'd like to pick up the discussion from a few months ago, and propose a new
sighash flag, `SIGHASH_NOINPUT`, that removes the commitment to the previous
output. This was previously mentioned on the list by Joseph Poon [1], but was
never formally proposed, so I wrote a proposal [2].
We have long known that `SIGHASH_NOINPUT` would be a great fit for Lightning.
They enable simple watch-towers, i.e., outsource the need to watch the
blockchain for channel closures, and react appropriately if our counterparty
misbehaves. In addition to this we just released the eltoo [3,4] paper which
describes a simplified update mechanism that can be used in Lightning, and other
off-chain contracts, with any number of participants.
By not committing to the previous output being spent by the transaction, we can
rebind an input to point to any outpoint with a matching output script and
value. The binding therefore is no longer explicit through a reference, but
through script compatibility, and the transaction ID reference in the input is a
hint to validators. The sighash flag is meant to enable some off-chain use-cases
and should not be used unless the tradeoffs are well-known. In particular we
suggest using contract specific key-pairs, in order to avoid having any unwanted
rebinding opportunities.
The proposal is very minimalistic, and simple. However, there are a few things
where we'd like to hear the input of the wider community with regards to the
implementation details though. We had some discussions internally on whether to
use a separate opcode or a sighash flag, some feeling that the sighash flag
could lead to some confusion with existing wallets, but given that we have
`SIGHASH_NONE`, and that existing wallets will not sign things with unknown
flags, we decided to go the sighash way. Another thing is that we still commit
to the amount of the outpoint being spent. The rationale behind this is that,
while rebinding to outpoints with the same value maintains the value
relationship between input and output, we will probably not want to bind to
something with a different value and suddenly pay a gigantic fee.
The deployment part of the proposal is left vague on purpose in order not to
collide with any other proposals. It should be possible to introduce it by
bumping the segwit script version and adding the new behavior.
I hope the proposal is well received, and I'm looking forward to discussing
variants and tradeoffs here. I think the applications we proposed so far are
quite interesting, and I'm sure there are many more we can enable with this
change.
Cheers,
Christian
[1] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/
2016-February/012460.html
[2] https://github.com/cdecker/bips/blob/noinput/bip-xyz.mediawiki
[3] https://blockstream.com/2018/04/30/eltoo-next-lightning.html
[4] https://blockstream.com/eltoo.pdf
_______________________________________________
bitcoin-dev mailing list
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
Christian Decker via bitcoin-dev
2018-05-01 17:32:32 UTC
Permalink
Raw Message
Post by Russell O'Connor via bitcoin-dev
At the risk of bikeshedding, shouldn't NOINPUT also zero out the
hashSequence so that its behaviour is consistent with ANYONECANPAY?
Good catch, must've missed that somehow. I'll amend the BIP accordingly.
Christian Decker via bitcoin-dev
2018-05-04 11:09:09 UTC
Permalink
Raw Message
It seems to me, that `SIGHASH_NOINPUT` may help make some protocol
integrate better with existing wallets.
Depends on which end of a transaction the existing wallet is: existing
wallets will refuse to sign a transaction with an unknown sighash flag,
but if the wallet is creating the output that'll later be spent using a
`SIGHASH_NOINPUT` transaction it won't (and shouldn't) care.
I remember vaguely that `SIGHASH_NOINPUT` was also mentioned before in
LN discussions, when the issue of transaction malleation was
considered (before SegWit, being totally uncontroversial, was
massively adopted). The sketch below, I believe, is somewhat
consistent with how it could have been used in funding a channel.
I consider `SIGHASH_NOINPUT` to be a poor-man's malleability fix, since
it comes with some baggage. Without trying to undermine my own proposal,
but address reuse in combination with binding through script, can lead
to very unexpected results. You need to be very careful about where you
allow rebinding, hence the warnings in the proposal.
Consider a CoinSwap protocol. Each side writes a transaction that
pays out to an ordinary 2-of-2 multisig address. But before each side
writes and signs that transaction, it first demands a timelocked
backout transaction to let them recover their own funds in case it
falls through (more generally, every offchain protocol has a similar
setup stage where some way to back out is signed before all parties
enter into the contract).
...
With `SIGHASH_NOINPUT`, we can indeed implement such a walletless
CoinSwap (or other protocol) software. We only need to provide the
public keys that will be used in the initial 2-of-2, and the other
side can create a signature with `SIGHASH_NOINPUT` flag.
I was wondering whether we could actually skip one communication round
w.r.t. the previously described CoinSwap protocol, but it turns out we
need to at least exchange public keys before actually moving any
funds. Would have been nice to do spontaneous CoinSwaps.
The setup of the CoinSwap then goes this way. The swapping nodes
exchange public keys (two for each side in this case), they agree on
who gets to move first in the swap and who generates the preimage, and
then they agree on what the backout transactions look like (in
particular, they agree on the address the backout transactions spend)
and create signatures, with `SIGHASH_NOINPUT`. In particular, the
signatures do not commit to the txid of the transaction that they
authorize spending. The CoinSwap sofwares then turn around to their
users and say "okay, send to this address", the users initiate the
swap using their normal wallet software, the CoinSwap software
monitors only the address it asked the user to use, then when it
appears onchain (the CoinSwap software does not even need to track the
mempool) it continues with the HTLC offers and preimage exchanges
until the protocol completes.
1. A user buys Bitcoin from an exchange. The exchange operates a
wallet which they credit when the user buys Bitcoin.
2. The user starts a CoinSwap, giving the destination address from
their cold-storage wallet.
3. The CoinSwap tells the user an address to send to. The user
withdraws money from the exchange using that address as destination (1
transaction)
4. The user waits for the CoinSwap to finish, which causes the funds
to appear in their cold-storage wallet (1 transaction).
1. A user buys Bitcoin from an exchange.
2. The user withdraws the funds from the exchange to a CoinSwap
implementation wallet (1 transaction).
3. The user performs a CoinSwap which goes back to the CoinSwap
implementation wallet (2 transactions).
4. The user sends from the CoinSwap wallet to their cold storage (1
transaction). (granted, the CoinSwap implementation could offer a
feature that immediately transfers the swapped funds to some other
wallet, but we still cannot get around the transfer from the exchange
to the CoinSwap wallet)
A drawback of course, is that `SIGHASH_NOINPUT` is an unusual flag to
use; it immediately paints the user as using some special protocol.
So much for `SIGHASH_NOINPUT` CoinSwap.
By providing a new use-case you are contributing to the obfuscation of
this technique. The more normal the use of `SIGHASH_NOINPUT` becomes the
less an observer can learn from it being used. In combination with MAST,
Taproot or Graftroot we can further hide the details of the executed
protocol :-)
ZmnSCPxj via bitcoin-dev
2018-05-04 14:25:46 UTC
Permalink
Raw Message
Good morning Christian,
Post by Christian Decker via bitcoin-dev
It seems to me, that `SIGHASH_NOINPUT` may help make some protocol
integrate better with existing wallets.
Depends on which end of a transaction the existing wallet is: existing
wallets will refuse to sign a transaction with an unknown sighash flag,
but if the wallet is creating the output that'll later be spent using a
`SIGHASH_NOINPUT` transaction it won't (and shouldn't) care.
Yes, the intent is that specialized utilities (like the CoinSwap I gave as an example) would be the ones signing with `SIGHASH_NOINPUT`, with the existing wallet generating the output that will be spent with a `SIGHASH_NOINPUT`.

The issue is that some trustless protocols have an offchain component, where some kind of backoff transaction is created, and the creation involves the 3 steps (1) make but do not sign&broadcast a funding tx (2) make and sign a backoff transaction that spends the funding tx (3) sign and broadcast the original funding tx. This holds for Poon-Dryja, your new eltoo Decker-Russell-Osuntokun, and CoinSwap. Commodity user wallets and exchange wallets only support the most basic "make tx, sign, broadcast", and integrating with the generalized funding transaction pattern is not possible. `SIGHASH_NOINPUT` allows us to make the backoff transaction first, then make the funding transaction via the usual "make tx, sign, broadcast" procedure that commodity wallets implement.
Post by Christian Decker via bitcoin-dev
A drawback of course, is that `SIGHASH_NOINPUT` is an unusual flag to
use; it immediately paints the user as using some special protocol.
So much for `SIGHASH_NOINPUT` CoinSwap.
By providing a new use-case you are contributing to the obfuscation of
this technique. The more normal the use of `SIGHASH_NOINPUT` becomes the
less an observer can learn from it being used. In combination with MAST,
Taproot or Graftroot we can further hide the details of the executed
protocol :-)
Thinking about it further, it turns out that in the cooperative completion of the protocol, we do not need to sign anything using `SIGHASH_NOINPUT`, but can use the typical `SIGHASH_ALL`. Indeed all generalized funding transaction patterns can be updated to use this: only the initial backout transaction needs to be signed with `SIGHASH_NOINPUT`, all others can be signed with `SIGHASH_ALL`, including the protocol conclusion transaction.

1. In CoinSwapCS, TX-0 and TX-1 are funding transactions. The backoff transaction is the TX-2 and TX-3 transactions. Only TX-2 and TX-3 need be signed with `SIGHASH_NOINPUT`. TX-4 and TX-5, which complete the protocol and hide the swap, can be signed with `SIGHASH_ALL`.

2. In Poon-Dryja, the backoff transaction is the very first commitment transaction. Again only that transaction needs to be signed with `SIGHASH_NOINPUT`: future commitment transactions as well as the mutual close transaction can be signed with `SIGHASH_ALL`.

3. In Decker-Russell-Osuntokun, the backoff transaction is the trigger transaction and the first settlement transaction. The trigger transaction can sign with `SIGHASH_NOINPUT`. Then only the final settlement (i.e. mutual close) can be signed with `SIGHASH_ALL`.

Thus if the protocol completes cooperatively, the only onchain evidence is that a 2-of-2 multisig is spent, and signed using `SIGHASH_ALL`, and the money goes to some ordinary P2WPKH addresses.

The advantage, as I mentioned, is that these protocols can be implemented using "walletless" software: the special protocol software runs the protocol up to the point that they get the backoff transaction, then asks the user to pay an exact amount to an exact address. This has a number of advantages:

1. RBF can be supported if the wallet software supports RBF. In particular without `SIGHASH_NOINPUT` the protocol would require renegotiation of a new backoff transaction in order to support RBF (and in particular the protocol spec would need to be designed in the first place to consider that possibility!), and would become more complicated since while a new backoff transaction is being negotiated, the previous version of the funding transaction may get confirmed. With `SIGHASH_NOINPUT` all the specialized protocol software needs to do, is to watch for a transaction paying to the given address to be confirmed deeply enough to be unlikely to be reorganized: there is no need to renegotiate a backoff transaction, because whatever transaction gets confirmed, as long as it pays to the address with a given amount, the signature for the backoff transaction remains valid for it.
2. Wallet software of any kind can be used in conjunction with special protocol software of any kind. Hardware wallets do not need to implement LN: the LN software starts a channel and gives a P2WSH address that hardware wallets know how to pay to. Ditto for exchange wallets. Etc. And if a future protocol arises that uses the funding transaction pattern again, then again existing wallets can integrate with those protocols via P2WSH address.
3. Special protocol software need not implement even basic wallet functionality: they can just focus on the specific protocol they implement. Consider how until late last year c-lightning needed a separate RPC command to inform it that it received funds, and a few months ago we had many issues with UTXOs in our database getting out of sync with the blockchain (why we implemented `dev-rescan-outputs`).

Regards.
ZmnSCPxj
Christian Decker via bitcoin-dev
2018-05-07 19:40:46 UTC
Permalink
Raw Message
Given the general enthusiasm, and lack of major criticism, for the
`SIGHASH_NOINPUT` proposal, I'd like to formally ask the BBEs (benevolent
BIP editors) to be assigned a BIP number. I have hacked together a
simple implementation of the hashing implementation in Bitcoin Core [1]
though I think it's unlikely to sail through review, and given the lack
of ground-work on witness V1 scripts, I can't really test it now, and
only the second commit is part of the implementation itself.

One issue that was raised off list was that some fork coins have used
sighash 0x40 as FORKID. This does not conflict with this proposal since
the proposal only applies to segwit transactions, which the fork coins
have explicitly disabled :-)

I'm looking forward to discussing how to we can move forward to
implementing this proposal, and how we can combine multiple proposals
into the next soft-fork.

Cheers,
Christian

[1] https://github.com/cdecker/bitcoin/tree/noinput
Anthony Towns via bitcoin-dev
2018-05-14 09:23:29 UTC
Permalink
Raw Message
The big concern I have with _NOINPUT is that it has a huge failure
case: if you use the same key for multiple inputs and sign one of them
with _NOINPUT, you've spent all of them. The current proposal kind-of
limits the potential damage by still committing to the prevout amount,
but it still seems a big risk for all the people that reuse addresses,
which seems to be just about everyone.
If I can convince you to sign with SIGHASH_NONE, it's already a problem
today.
So, I don't find that very compelling: "there's already a way to lose
your money, so it's fine to add other ways to lose your money". And
again, I think NOINPUT is worse here, because a SIGHASH_NONE signature
only lets others take the coin you're trying to spend, messing up when
using NOINPUT can cause you to lose other coins as well (with caveats).
[...]
In a world where SIGHASH_NONE didn't exist, this might be an argument :)
I could see either dropping support for SIGHASH_NONE for segwit
v1 addresses, or possibly limiting SIGHASH_NONE in a similar way to
limiting SIGHASH_NOINPUT. Has anyone dug through the blockchain to see
if SIGHASH_NONE is actually used/useful?
That was also suggested by Mark Friedenbach, but I think we'll end up
with more "magic key" a-la Schnorr/taproot/graftroot and less script in
future.
Taproot and graftroot aren't "less script" at all -- if anything they're
the opposite in that suddenly every address can have a script path.
I think NOINPUT has pretty much the same tradeoffs as taproot/graftroot
scripts: in the normal case for both you just use a SIGHASH_ALL
signature to spend your funds; in the abnormal case for NOINPUT, you use
a SIGHASH_NOINPUT (multi)sig for unilateral eltoo closes or watchtower
penalties, in the abnormal case for taproot/graftroot you use a script.
That means we'd actually want a different Segwit version for
"NOINPUT-can-be-used", which seems super ugly.
That's backwards. If you introduce a new opcode, you can use the existing
segwit version, rather than needing segwit v1. You certainly don't need
v1 segwit for regular coins and v2 segwit for NOINPUT coins, if that's
where you were going?

For segwit v0, that would mean your addresses for a key "X", might be:

[pubkey] X
- not usable with NOINPUT
[script] 2 X Y 2 CHECKMULTISIG
- not usable with NOINPUT
[script] 2 X Y 2 CHECKMULTISIG_1USE_VERIFY
- usable with NOINPUT (or SIGHASH_ALL)

CHECKMULTISIG_1USE_VERIFY being soft-forked in by replacing an OP_NOP,
of course. Any output spendable via a NOINPUT signature would then have
had to have been deliberately created as being spendable by NOINPUT.

For a new segwit version with taproot that likewise includes an opcode,
that might be:

[taproot] X
- not usable with NOINPUT
[taproot] X or: X CHECKSIG_1USE
- usable with NOINPUT

If you had two UTXOs (with the same value), then if you construct
a taproot witness script for the latter address it will look like:

X [X CHECKSIG_1USE] [sig_X_NOINPUT]

and that signature can't be used for addresses that were just intending
to pay to X, because the NOINPUT sig/sighash simply isn't supported
without a taproot path that includes the CHECKSIG_1USE opcode.

In essence, with the above construction there's two sorts of addresses
you generate from a public key X: addresses where you spend each coin
individually, and different addresses where you spend the wallet of
coins with that public key (and value) at once; and that remains the
same even if you use a single key for both.

I think it's slightly more reasonable to worry about signing with NOINPUT
compared to signing with SIGHASH_NONE: you could pretty reasonably setup
your (light) bitcoin wallet to not be able to sign (or verify) with
SIGHASH_NONE ever; but if you want to use lightning v2, it seems pretty
likely your wallet will be signing things with SIGHASH_NOINPUT. From
there, it's a matter of having a bug or a mistake cause you to
cross-contaminate keys into your lightning subsystem, and not be
sufficiently protected by other measures (eg, muSig versus checkmultisig).

(For me the Debian ssh key generation bug from a decade ago is sufficient
evidence that people you'd think are smart and competent do make really
stupid mistakes in real life; so defense in depth here makes sense even
though you'd have to do really stupid things to get a benefit from it)

The other benefit of a separate opcode is support can be soft-forked in
independently of a new segwit version (either earlier or later).

I don't think the code has to be much more complicated with a separate
opcode; passing an extra flag to TransactionSignatureChecker::CheckSig()
is probably close to enough. Some sort of flag remains needed anyway
since v0 and pre-segwit signatures won't support NOINPUT.

Cheers,
aj
Christian Decker via bitcoin-dev
2018-05-15 14:28:22 UTC
Permalink
Raw Message
Post by Anthony Towns via bitcoin-dev
The big concern I have with _NOINPUT is that it has a huge failure
case: if you use the same key for multiple inputs and sign one of them
with _NOINPUT, you've spent all of them. The current proposal kind-of
limits the potential damage by still committing to the prevout amount,
but it still seems a big risk for all the people that reuse addresses,
which seems to be just about everyone.
If I can convince you to sign with SIGHASH_NONE, it's already a problem
today.
So, I don't find that very compelling: "there's already a way to lose
your money, so it's fine to add other ways to lose your money". And
again, I think NOINPUT is worse here, because a SIGHASH_NONE signature
only lets others take the coin you're trying to spend, messing up when
using NOINPUT can cause you to lose other coins as well (with caveats).
`SIGHASH_NOINPUT` is a rather powerful tool, but has to be used
responsibly, which is why we always mention that it shouldn't be used
lightly. Then again all sighash flags can be dangerous if not well
understood. Think for example `SIGHASH_SINGLE` with it's pitfall when
the input has no matching output, or the already mentioned SIGHASH_NONE.

From a technical, and risk, point of view I don't think there is much
difference between a new opcode or a new sighash flag, with the
activation being the one exception. I personally believe that a segwit
script bump has cleaner semantics than soft-forking in a new opcode
(which has 90% overlap with the existing checksig and checkmultisig
opcodes).
Post by Anthony Towns via bitcoin-dev
[...]
In a world where SIGHASH_NONE didn't exist, this might be an argument :)
I could see either dropping support for SIGHASH_NONE for segwit
v1 addresses, or possibly limiting SIGHASH_NONE in a similar way to
limiting SIGHASH_NOINPUT. Has anyone dug through the blockchain to see
if SIGHASH_NONE is actually used/useful?
That's a good point, I'll try looking for it once I get back to my full
node :-) And yes, `SIGHASH_NONE` should also come with all the warning
signs about not using it without a very good reason.
Post by Anthony Towns via bitcoin-dev
That was also suggested by Mark Friedenbach, but I think we'll end up
with more "magic key" a-la Schnorr/taproot/graftroot and less script in
future.
Taproot and graftroot aren't "less script" at all -- if anything they're
the opposite in that suddenly every address can have a script path.
I think NOINPUT has pretty much the same tradeoffs as taproot/graftroot
scripts: in the normal case for both you just use a SIGHASH_ALL
signature to spend your funds; in the abnormal case for NOINPUT, you use
a SIGHASH_NOINPUT (multi)sig for unilateral eltoo closes or watchtower
penalties, in the abnormal case for taproot/graftroot you use a script.
That's true for today's uses of `SIGHASH_NOINPUT` and others, but there
might be other uses that we don't know about in which noinput isn't just
used for the contingency, handwavy I know. That's probably not the case
for graftroot/taproot, but I'm happy to be corrected on that one.

Still, these opcodes and hash flags being mainly used for contingencies,
doesn't remove the need for these contingency options to be enforced
on-chain.
Post by Anthony Towns via bitcoin-dev
That means we'd actually want a different Segwit version for
"NOINPUT-can-be-used", which seems super ugly.
That's backwards. If you introduce a new opcode, you can use the existing
segwit version, rather than needing segwit v1. You certainly don't need
v1 segwit for regular coins and v2 segwit for NOINPUT coins, if that's
where you were going?
[pubkey] X
- not usable with NOINPUT
[script] 2 X Y 2 CHECKMULTISIG
- not usable with NOINPUT
[script] 2 X Y 2 CHECKMULTISIG_1USE_VERIFY
- usable with NOINPUT (or SIGHASH_ALL)
CHECKMULTISIG_1USE_VERIFY being soft-forked in by replacing an OP_NOP,
of course. Any output spendable via a NOINPUT signature would then have
had to have been deliberately created as being spendable by NOINPUT.
The main reason I went for the sighash flag instead of an opcode is that
it has clean semantics, allows for it to be bundled with a number of
other upgrades, and doesn't use up NOP-codes, which I was lectured
for my normalized tx BIP (BIP140) is a rare resource that should be used
sparingly. The `SIGHASH_NOINPUT` proposal is minimal, since it enhances
4 existing opcodes. If we were to do that with new opcodes we'd either
want a multisig and a singlesig variant, potentially with a verify
variant each. That's a lot of opcodes.

The proposal being minimal should also help against everybody trying to
get their favorite feature added, and hopefully streamline the
discussion.
Post by Anthony Towns via bitcoin-dev
For a new segwit version with taproot that likewise includes an opcode,
[taproot] X
- not usable with NOINPUT
[taproot] X or: X CHECKSIG_1USE
- usable with NOINPUT
If you had two UTXOs (with the same value), then if you construct
X [X CHECKSIG_1USE] [sig_X_NOINPUT]
and that signature can't be used for addresses that were just intending
to pay to X, because the NOINPUT sig/sighash simply isn't supported
without a taproot path that includes the CHECKSIG_1USE opcode.
In essence, with the above construction there's two sorts of addresses
you generate from a public key X: addresses where you spend each coin
individually, and different addresses where you spend the wallet of
coins with that public key (and value) at once; and that remains the
same even if you use a single key for both.
I think it's slightly more reasonable to worry about signing with NOINPUT
compared to signing with SIGHASH_NONE: you could pretty reasonably setup
your (light) bitcoin wallet to not be able to sign (or verify) with
SIGHASH_NONE ever; but if you want to use lightning v2, it seems pretty
likely your wallet will be signing things with SIGHASH_NOINPUT. From
there, it's a matter of having a bug or a mistake cause you to
cross-contaminate keys into your lightning subsystem, and not be
sufficiently protected by other measures (eg, muSig versus checkmultisig).
I think the same can be addressed by simply having the wallet use a
different derivation path for keys that it is willing to sign with
NOINPUT. I sort of dislike having a direct dependency on taproot, i.e.,
allowing noinput only in taproot scripts, since that isn't a done deal
either. Without that direct dependency, having the noinput path and the
sighash_all path be differentiated in the script leaks the details
on-chain, bloating the UTXO set, and leaking details about our contract.

Also isn't the same issue true for a separate opcode?
Post by Anthony Towns via bitcoin-dev
(For me the Debian ssh key generation bug from a decade ago is sufficient
evidence that people you'd think are smart and competent do make really
stupid mistakes in real life; so defense in depth here makes sense even
though you'd have to do really stupid things to get a benefit from it)
Totally agree, however one could argue that increased code complexity
is a major contributor to security issues, and I'm still convinced that
the hashflag is the simplest and cleanest approach to getting this
feature implemented.

That being said, I think the soft-forked opcode is also a good option,
if we can get agreement on the details in a reasonable amount of time.
Post by Anthony Towns via bitcoin-dev
The other benefit of a separate opcode is support can be soft-forked in
independently of a new segwit version (either earlier or later).
That can both be a positive as well as a negative, since a bundle of
complementing features likely is easier to get reviewed and activated.
Post by Anthony Towns via bitcoin-dev
I don't think the code has to be much more complicated with a separate
opcode; passing an extra flag to TransactionSignatureChecker::CheckSig()
is probably close to enough. Some sort of flag remains needed anyway
since v0 and pre-segwit signatures won't support NOINPUT.
That's moving the fanout for sighash_all vs sighash_none from the opcode
up to the interpreter, right.

Cheers,
Christian

Loading...