-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
Draft for Extra Data / HASH160 Support #1587
Open
JeremyRubin
wants to merge
2
commits into
bitcoin:master
Choose a base branch
from
JeremyRubin:ctv-v2
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
<pre> | ||
BIP: 119.2 (Pending Assignment) | ||
Layer: Consensus (soft fork) | ||
Title: CHECKTEMPLATEVERIFY V2 | ||
Author: Jeremy Rubin <[email protected]> | ||
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0119 | ||
Status: Draft | ||
Type: Standards Track | ||
Created: 2024-05-06 | ||
License: BSD-3-Clause | ||
</pre> | ||
|
||
==Abstract== | ||
|
||
This BIP proposes extensions to OP_CHECKTEMPLATEVERIFY BIP-119 as enhancements | ||
for LN Symmetry based constructions which use CTV and CSFS. | ||
|
||
|
||
==Summary== | ||
|
||
Adds a 20-byte CTV hash using HASH160 digest to save 12 bytes per script. Adds | ||
a 1-byte flag (with no bits set) that allows for arbitrary data to be committed | ||
to inside the CTV hash. | ||
|
||
==Motivation== | ||
|
||
LN Symmetry prefers scripts as small as possible. Allowing the use of HASH160 | ||
can allow users to reduce fees in exchange for minor loss of security. | ||
|
||
LN Symmetry also sometimes requires additional committed data for data | ||
availability purposes. When using BIP-118 APO, this extra data can be | ||
(although, according to BIP-341/342 should not be) placed in the Annex. As CTV | ||
does not commit to the annex, additional data can be committed to in an | ||
OP_RETURN. However, OP_RETURNs are inefficient as they require 8 bytes of | ||
value plus a few VarInts to encode sizes, and use non discounted blockspace. | ||
Instead, committing to with CTV extra values on the stack can avoid these | ||
overheads. | ||
|
||
|
||
==Detailed Specification== | ||
|
||
The below code is the main logic for verifying CHECKTEMPLATEVERIFY, described | ||
in pythonic pseudocode, with these modifications. The canonical specification | ||
for the semantics of OP_CHECKTEMPLATEVERIFY as implemented in C++ in the | ||
context of Bitcoin Core can be seen in the reference implementation (TODO). | ||
|
||
The execution of the opcode is as follows: | ||
<source lang="python"> | ||
def execute_bip_119_v2(self): | ||
# Before soft-fork activation / failed activation | ||
# continue to treat as NOP4 | ||
if not self.flags.script_verify_default_check_template_verify_hash: | ||
# Potentially set for node-local policy to discourage premature use | ||
if self.flags.script_verify_discourage_upgradable_nops: | ||
return self.errors_with(errors.script_err_discourage_upgradable_nops) | ||
return self.return_as_nop() | ||
|
||
# CTV always requires at least one stack argument | ||
if len(self.stack) < 1: | ||
return self.errors_with(errors.script_err_invalid_stack_operation) | ||
|
||
# CTV only verifies the hash against a 32 byte argument | ||
if len(self.stack[-1]) == 32: | ||
# Ensure the precomputed data required for anti-DoS is available, | ||
# or cache it on first use | ||
if self.context.precomputed_ctv_data == None: | ||
self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data() | ||
|
||
# If the hashes do not match, return error | ||
if stack[-1] != self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data): | ||
return self.errors_with(errors.script_err_template_mismatch) | ||
|
||
return self.return_as_nop() | ||
|
||
# verifies the hash against a 20 byte argument | ||
if len(self.stack[-1]) == 20: | ||
|
||
# Before soft-fork activation / failed activation | ||
# continue to treat as NOP4 | ||
if not self.flags.script_verify_default_check_template_verify_hash_v2: | ||
# Potentially set for node-local policy to discourage premature use | ||
if self.flags.script_verify_discourage_upgradable_nops: | ||
return self.errors_with(errors.script_err_discourage_upgradable_nops) | ||
return self.return_as_nop() | ||
|
||
|
||
# Ensure the precomputed data required for anti-DoS is available, | ||
# or cache it on first use | ||
if self.context.precomputed_ctv_data == None: | ||
self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data() | ||
|
||
# If the hashes do not match, return error | ||
if stack[-1] != ripemd(self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data)): | ||
return self.errors_with(errors.script_err_template_mismatch) | ||
|
||
return self.return_as_nop() | ||
|
||
# verifies the hash against a 21 byte argument and extra data | ||
if len(self.stack[-1]) == 21: | ||
# CTV+data always requires at least two stack argument | ||
if len(self.stack) < 2: | ||
return self.errors_with(errors.script_err_invalid_stack_operation) | ||
|
||
# Before soft-fork activation / failed activation | ||
# continue to treat as NOP4 | ||
if not self.flags.script_verify_default_check_template_verify_hash_v2 or self.stack[-1][-1] != 0: | ||
# Potentially set for node-local policy to discourage premature use | ||
if self.flags.script_verify_discourage_upgradable_nops: | ||
return self.errors_with(errors.script_err_discourage_upgradable_nops) | ||
return self.return_as_nop() | ||
|
||
|
||
# Ensure the precomputed data required for anti-DoS is available, | ||
# or cache it on first use | ||
if self.context.precomputed_ctv_data == None: | ||
self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data() | ||
|
||
# If the hashes do not match, return error | ||
if stack[-1][:-1] != ripemd(sha256(self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data) + sha256(stack[-2]))): | ||
return self.errors_with(errors.script_err_template_mismatch) | ||
|
||
return self.return_as_nop() | ||
|
||
# verifies the hash against a 33 byte argument and extra data | ||
if len(self.stack[-1]) == 33: | ||
# CTV+data always requires at least two stack argument | ||
if len(self.stack) < 2: | ||
return self.errors_with(errors.script_err_invalid_stack_operation) | ||
|
||
# Before soft-fork activation / failed activation | ||
# continue to treat as NOP4 | ||
if not self.flags.script_verify_default_check_template_verify_hash_v2 or self.stack[-1][-1] != 0: | ||
# Potentially set for node-local policy to discourage premature use | ||
if self.flags.script_verify_discourage_upgradable_nops: | ||
return self.errors_with(errors.script_err_discourage_upgradable_nops) | ||
return self.return_as_nop() | ||
|
||
|
||
# Ensure the precomputed data required for anti-DoS is available, | ||
# or cache it on first use | ||
if self.context.precomputed_ctv_data == None: | ||
self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data() | ||
|
||
# If the hashes do not match, return error | ||
if stack[-1][:-1] != sha256(self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data) + sha256(stack[-2])): | ||
return self.errors_with(errors.script_err_template_mismatch) | ||
|
||
return self.return_as_nop() | ||
|
||
# future upgrade can add semantics for this opcode with different length args | ||
# so discourage use when applicable | ||
if self.flags.script_verify_discourage_upgradable_nops: | ||
return self.errors_with(errors.script_err_discourage_upgradable_nops) | ||
else: | ||
return self.return_as_nop() | ||
</source> | ||
|
||
|
||
No additional DoS protection or caching is required, as the hashing overhead of | ||
the new opcode is similar to that of a regular OP_SHA256 or OP_HASH160. | ||
|
||
==Deployment== | ||
|
||
N/A | ||
==Reference Implementation== | ||
|
||
A reference implementation and tests are pending after conceptual agreement. | ||
|
||
|
||
===Alternatives=== | ||
|
||
Should `OP_CAT` be added to Bitcoin, one would be able to use script fragments | ||
that sign the CTV hash concatenated with the extra data, which would be | ||
equivalent to this. | ||
|
||
Should `CSFS` sign an arbitrary number of stack elements as a vector | ||
commitment, this would also be equivalent. | ||
|
||
This BIP could be pared down to just provide the 20-byte version for | ||
efficiency. | ||
|
||
==Copyright== | ||
|
||
This document is licensed under the 3-clause BSD license. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the things I'm having trouble following here is precisely why this extra byte allows for Extra Data to be committed to. As far as I can tell the extra byte ensures that there are at least two stack elements but doesn't actually verify what the first stack element is.
I assume that CTV's natural semantics already result in committing to the contents of that second stack element but the mechanism is not obvious to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this equation might help:
Sha256(CTVHASH(TX) || sha256(stack[-2])) == stack[-1][0:32]
more or less, check that the 32 bytes on the back of the stack match if you took the CTV hash and hashed it with some extra data.
The point is to enable signing stack[-1][0:32] with CSFS, which then also covers the extra data, allowing you to stuff arbitrary extra data into the witness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes now I see it. I got lost in the noise and didn't see the
-2
at the end here.I get it now. Thanks for explaining!