Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update BIP 118 for taproot, rename to ANYPREVOUT #943

Merged
merged 5 commits into from
Jul 8, 2021

Conversation

ajtowns
Copy link
Contributor

@ajtowns ajtowns commented Jul 9, 2020

Lots of updates to BIP 118 in light of taproot. cc @cdecker

Copy link
Contributor

@harding harding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gave it a quick read and didn't spot anything objectionable. One micro-nit.

bip-0118.mediawiki Outdated Show resolved Hide resolved
@mcelrath
Copy link

I suggest that you get a new BIP number for ANYPREVOUT and add "not recommended for implementation" to bip118 (including reasoning, please ;-).

The two approaches are conceptually distinct and it's worth keeping the other idea around for historical purposes, even if it's not pursued going forward. BIP118 as a segwit version has been around for over 3 years now.

Please just give us one or the other! We're dying out here! ;-)

@harding
Copy link
Contributor

harding commented Jul 11, 2020

The two approaches are conceptually distinct and it's worth keeping the other idea around for historical purposes

Concept ACK for updating. The original BIP118 proposal will remain available via git history, so no information is lost by updating it. Noinput as its own separate segwit version never had any traction AFAICT---I think almost everyone has wanted this to be either a part of a larger soft fork or an add-on soft fork.

@ajtowns ajtowns force-pushed the bip-anyprevout branch 2 times, most recently from b001d42 to ac73eed Compare July 13, 2020 06:43
@cdecker
Copy link
Contributor

cdecker commented Jul 17, 2020

That was the rationale for proposing an update instead of leaving noinput lingering. noinput alone was lacking the details to make it work within taproot, and the update adds all the necessary details to make the proposal compatible with taproot. Given the timing of the taproot and the noinput proposal we tried to make the two independent by not adding any dependencies between them.

With taproot making good progress, and the shrinking probability of a raw noinput proposal without taproot integration making progress, it is desirable imho to replace the raw proposal with the integrated one.

@luke-jr
Copy link
Member

luke-jr commented Aug 20, 2020

poke @ajtowns @cdecker

Copy link
Contributor

@benthecarman benthecarman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth adding a section about recommendations for wallet devs on how to handle if funds are received to an address that has BIP 118 pub key, I would expect that they should immediately spend it to another address if they already given out a SIGHASH_ANYPREVOUTANYSCRIPT signature and do not want the newly received funds spendable by the parties with the signature.

Comment on lines 162 to 177
Further, for a chain of transactions using the same <code>scriptPubKey</code> and value, and only authenticated via ANYPREVOUT signatures (as envisioned in eltoo for failure cases), it may be possible for any third party to malleate the transactions (and their txids) without having access to any of the private keys, particularly by omitting intermediate transactions.

This form of malleation can be dealt with by the child transactions also using ANYPREVOUT signatures -- when a parent transaction is malleated, its children can simply be adjusted to reference the new txid as the input and the ANYPREVOUT signatures remain valid.

However child transactions that are authorised by a <code>SIGHASH_ALL</code> or <code>SIGHASH_ANYONECANPAY</code> signature will need new signatures if their inputs are malleated in this way.
This risk may be mitigated somewhat by using [[bip-0068.mediawiki|BIP 68]]/[[bip-0112.mediawiki|BIP 112]] relative time locks before spending a UTXO that had been authorised via an ANYPREVOUT signature with <code>SIGHASH_ALL</code> or <code>SIGHASH_ANYONECANPAY</code>: a relative timelock can ensure that the inputs have enough confirmations that they can only be replaced in the event of a large block reorg.
Note that this approach has drawbacks: relative timelocks prevent fee-bumping via child-pays-for-parent, and have the obvious drawback of making the funds temporarily unusable until the timelock expires.

==== Privacy considerations ====

It is expected that ANYPREVOUT signatures will only be rarely used in practice.
Protocol and wallet designers should aim to have their transactions use Taproot key path spends whenever possible, both for efficiency reasons due to the lower transaction weight, but also for privacy reasons to avoid third parties being able to distinguish their transactions from those of other protocols.

Transactions that do use ANYPREVOUT signatures will therefore reveal information about the transaction, potentially including that cooperation was impossible, or what protocol or software in use (due to the details of the script).

In order to maximise privacy, it is therefore recommended that protocol designers only use BIP 118 public keys in scripts that will be spent using at least one ANYPREVOUT signature, and either use key path spends or alternate scripts in the taproot merkle tree for any spends that can be authorised without ANYPREVOUT signatures.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: change these "ANYPREVOUT"s to "ANYPREVOUT"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left "ANYPREVOUT signatures" as regular text since it's talking about the concept, and only used <code> markup for SIGHASH_ANYPREVOUT and SIGHASH_ANYPREVOUTANYSCRIPT. I think that's reasonable, so keeping it that way at present... (Have made a couple of tweaks while rebasing though)

bip-0118.mediawiki Outdated Show resolved Hide resolved
bip-0118.mediawiki Show resolved Hide resolved
@cdecker
Copy link
Contributor

cdecker commented Sep 18, 2020

It might be worth adding a section about recommendations for wallet devs on how to handle if funds are received to an address that has BIP 118 pub key, I would expect that they should immediately spend it to another address if they already given out a SIGHASH_ANYPREVOUTANYSCRIPT signature and do not want the newly received funds spendable by the parties with the signature.

Our usual approach to this is "if you don't know how to handle ANYPREVOUT scripts you should not signal support for BIP118", and the wallets sending to you should never use BIP118". Having consumer wallets that do not require BIP118 support handle it is undesirable, and imho any guidance on how to handle them might give the contrary impression.

@luke-jr
Copy link
Member

luke-jr commented Oct 5, 2020

What is the status here? Can we merge it?

@maaku
Copy link
Contributor

maaku commented Oct 12, 2020

I just want to say that it is horribly confusing to have a standards document be completely rewritten to describe a totally different idea. This is a very atypical thing to do. If it's a new approach, please make a new BIP.

@cdecker
Copy link
Contributor

cdecker commented Oct 12, 2020

It's not really new, it just adds the details for Taproot and addresses some concerns that have been raised during the discussion regarding replay-attacks. IMHO this is exactly the goal of updates to the BIPs.

@luke-jr
Copy link
Member

luke-jr commented Oct 12, 2020

Indeed, it's not like it was even Proposed yet, just a Draft.

@cdecker
Copy link
Contributor

cdecker commented Oct 12, 2020

I'll soon have a bit more time to dig into BIP 118, and I have spoken with a number of people willing to join a review club to work through the proposal. If anybody is interested in joining a public discussion we can set something up :-)

But don't want to distract from the Taproot effort, which deserves all the attention it can get, and is the basis for anyprevout.

@instagibbs
Copy link
Member

I think now is a good time to revive public discussion efforts?

@ajtowns ajtowns marked this pull request as ready for review June 9, 2021 22:33
@ajtowns
Copy link
Contributor Author

ajtowns commented Jun 9, 2021

Rebased, removed "draft" marker on PR, so should be okay for ACKs and eventual merge

@kallewoof
Copy link
Member

There's a lot of style changes mixed in with contextual changes so it's hard to determine what is a style fix vs what is new content. It would be helpful if commit number 1 was a pure style tweak followed by the actual changes in subsequent commit(s).

@ajtowns
Copy link
Contributor Author

ajtowns commented Jun 11, 2021

There's a lot of style changes mixed in with contextual changes so it's hard to determine what is a style fix vs what is new content.

It's pretty much entirely new content, I don't think there's much you can extract as just a style fix?

bip-0118.mediawiki Outdated Show resolved Hide resolved
@JeremyRubin
Copy link
Contributor

Is there a current reference implementation?

Trying to figure out presently if the BIP is trying to imply a tap leaf with 0x01 CHECKSIG has the effect of being equivalent to <0x01 || internal key> checksig or not (it seems implied by the bip language but not explicit enough imo).

@ajtowns
Copy link
Contributor Author

ajtowns commented Jun 12, 2021

Is there a current reference implementation?

There's a reference implementation at https://github.com/ajtowns/bitcoin/tree/202101-anyprevout but it's not current both in that it's missing at least the change to have ANYPREVOUTANYSCRIPT not commit to the amount, is some months out of date, and may be buggy.

Trying to figure out presently if the BIP is trying to imply a tap leaf with 0x01 CHECKSIG has the effect of being equivalent to <0x01 || internal key> checksig or not (it seems implied by the bip language but not explicit enough imo).

I'm not sure what's unclear about:

To convert a 1-byte BIP 118 public key for use with BIP 340, simply use the 32-byte taproot internal key, p, as defined in BIP 341.
To convert a 33-byte BIP 118 public key for use with BIP 340, simply remove the 0x01 prefix and use the remaining 32 bytes.

If your internal key is G, ie, "79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798" then doing either 210179BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798AC (push the 32-byte key prefixed by 0x01, then CHECKSIG) or 51AC (OP_1 and CHECKSIG) will result in a checksig operation against "G" as the BIP118 public key.

@JeremyRubin
Copy link
Contributor

I'm not in love with the 0x01 to mean an anyprevout key based on the internal PK.

I think that this sort of mechanism is more generally useful (e.g., I imagine the script USE_INTERNAL CHECKSIGVERIFY SHA256 <H> EQUAL could be useful without APO because bip341 commits to the spend script).

I also think that 0x01 makes it so that there is a public key which is "computable" using script math, which is kind of weird (or at least merits consideration)? I mean I suppose <something> sha256 also is a 32 byte value, but conceivably finding d. dG == sha256(x) is hard?

bip-0118.mediawiki Show resolved Hide resolved
bip-0118.mediawiki Outdated Show resolved Hide resolved
@ajtowns
Copy link
Contributor Author

ajtowns commented Jun 12, 2021

I think that this sort of mechanism is more generally useful (e.g., I imagine the script USE_INTERNAL CHECKSIGVERIFY SHA256 <H> EQUAL could be useful without APO because bip341 commits to the spend script).

You could define the single-byte pubkey "0x81" (ie the value OP_1NEGATE pushes onto the stack) to be treated as the internal public key with the bip342 signature digest and get that sort of behaviour. The key and/or signature needs to encode what digest is going to be used however; but if you're happy for the signature to encode the digest, then just using the APO capable OP_1 with a non-ANYPREVOUT signature works.

I also think that 0x01 makes it so that there is a public key which is "computable" using script math, which is kind of weird (or at least merits consideration)? I mean I suppose <something> sha256 also is a 32 byte value, but conceivably finding d. dG == sha256(x) is hard?

CAT would also make public keys "computable" in this sense, except moreso since there would actually be multiple keys you could compute. But you can already write scripts that simply accept the pubkey as an input which is more flexible, and already in use since that's how P2PKH works.

It is expected that ANYPREVOUT signatures will only be rarely used in practice.
Protocol and wallet designers should aim to have their transactions use Taproot key path spends whenever possible, both for efficiency reasons due to the lower transaction weight, but also for privacy reasons to avoid third parties being able to distinguish their transactions from those of other protocols.

Transactions that do use ANYPREVOUT signatures will therefore reveal information about the transaction, potentially including that cooperation was impossible, or what protocol or software in use (due to the details of the script).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small fix for a typo:

Suggested change
Transactions that do use ANYPREVOUT signatures will therefore reveal information about the transaction, potentially including that cooperation was impossible, or what protocol or software in use (due to the details of the script).
Transactions that do use ANYPREVOUT signatures will therefore reveal information about the transaction, potentially including that cooperation was impossible, or what protocol or software was used (due to the details of the script).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@luke-jr
Copy link
Member

luke-jr commented Jul 2, 2021

@cdecker Think this is mergable? Even if not perfect, it can continue to be revised...

As a result, a single signature for a third, even later transaction must be able to spend both the prior transactions, even though they have a different tapscript.
On the other hand, these cases also provide a good reason to have the option to commit to the script: because each transaction has a new script, committing to the script allows you to produce a signature that applies to precisely one of these transactions.
In the eltoo case, this allows you to have a signature for an update transaction that can be applied to any prior update, and a signature for a settlement transaction that applies only to the corresponding update transaction, while using the same key for both, which in turn allows for a more compact script.
</ref> and value <ref>'''Why (and why not) commit to the input value?'''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i understand correctly:

APO: Commits to value
APOAS: Doesn't commit to value

Can you better justify why we don't also want ANYPREVOUTANYVALUE and ANYPREVOUTANYSCRIPTSPECIFICVALUE?

@JeremyRubin
Copy link
Contributor

In general, one thing that strikes me is that when anyprevout is used for eltoo you're generally doing a script like:

IF
    10 CSV DROP
    1::musigkey(As,Bs) CHECKSIG
ELSE
    <S+1> CLTV DROP
   1::musigkey(Au,Bu) CHECKSIG
ENDIF

This means that you're overloading the CLTV clause, which means it's impossible to use Eltoo and use a absolute lock time, it also means you have to use fewer than a billion sequences, and if you pick a random # to mask how many payments you've done / pick random gaps let's say that reduces your numbers in half. That may be enough, but is still relatively limited. There is also the issue that multiple inputs cannot be combined into a transaction if they have signed on different locktimes.

Since Eltoo is the primary motivation for ANYPREVOUT, it's worth making sure we have all the parts we'd need bundled together to see it be successful.

A few options come to mind that might be desirable in order to better serve the eltoo usecase

  1. Define a new CSV type (e.g. define (1<<31 && 1<<30) as being dedicated to eltoo sequences). This has the benefit of giving a per input sequence, but the drawback of using a CSV bit. Because there's only 1 CSV per input, this technique cannot be used with a sequence tag.
  2. CSFS -- it would be possible to take a signature from stack for an arbitrary higher number, e.g.:
IF
    10 CSV DROP
    1::musigkey(As,Bs) CHECKSIG
ELSE
    DUP musigkey(Aseq, BSeq) CSFSV <S+1> GTE VERIFY
   1::musigkey(Au,Bu) CHECKSIG
ENDIF

Then, posession of a higher signed sequence would allow for the use of the update path. However, the downside is that there would be no guarantee that the new state provided for update would be higher than the past one without a more advanced covenant.
3) Sequenced Signature: It could be set up such that ANYPREVOUT keys are tagged with a N byte sequence (instead of 1), and a part of the process of signature verification includes hashing a sequence on the signature itself.

E.g.

IF
    10 CSV DROP
    1::musigkey(As,Bs) CHECKSIG
ELSE
   <N>::musigkey(Au,Bu) CHECKSIG
ENDIF

To satisfy this clause, a signature <N+1>::S would be required. When validating the signature S, the APO digest would have to include the value <N+1>. It is non cryptographically checked that N+1 > N.
5) Similar to 3, but look at more values off the stack. This is also OK, but violates the principle of not making opcodes take variable numbers of things off the stack. Verify semantics on the extra data fields could ameliorate this concern, and it might make sense to do it that way.
4) Something in the Annex: It would also be possible to define a new generic place for lock times in the annex (to permit dual height/time relative/absolute, all per input. The pro of this approach is that it would be solving an outstanding problem for script that we want to solve anyways, the downside is that the Annex is totally undefined presently so it's unclear that this is an appropriate use for it.
5) Do Nothing :)

Overall I'm somewhat partial to option 3 as it seems to be closest to making ANYPREVOUT more precisely designed to support Eltoo. It would also be possible to make it such that if the tag N=1, then the behavior is identical to the proposal currently.

@JeremyRubin
Copy link
Contributor

It occurs to me this might be the wrong venue to discuss the above as this is larger change outside the changes to the BIP outstanding, so I will move discussion to the mailing list.

@cdecker
Copy link
Contributor

cdecker commented Jul 8, 2021

@cdecker Think this is mergable? Even if not perfect, it can continue to be revised...

I think it is excellent, let's ship it 🤓 We can do fine-tuning and corrections in separate PRs, agreed

@luke-jr luke-jr merged commit 150ab6f into bitcoin:master Jul 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet