-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
BIP442: OP_PAIRCOMMIT #1699
base: master
Are you sure you want to change the base?
BIP442: OP_PAIRCOMMIT #1699
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,320 @@ | ||||||||||||||
``` | ||||||||||||||
BIP: 442 | ||||||||||||||
Layer: Consensus (soft fork) | ||||||||||||||
Title: OP_PAIRCOMMIT | ||||||||||||||
Author: moonsettler <[email protected]> | ||||||||||||||
Brandon Black <[email protected]> | ||||||||||||||
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0442 | ||||||||||||||
Status: Draft | ||||||||||||||
Type: Standards Track | ||||||||||||||
Created: 2024-12-09 | ||||||||||||||
License: BSD-3-Clause | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
## Abstract | ||||||||||||||
|
||||||||||||||
This BIP describes a new tapscript opcode `OP_PAIRCOMMIT`, which | ||||||||||||||
provides limited vector commitment functionality in tapscript. | ||||||||||||||
|
||||||||||||||
## Summary | ||||||||||||||
|
||||||||||||||
When verifying taproot script spends having leaf version 0xc0 (as defined in | ||||||||||||||
[BIP-342]), we propose `OP_PAIRCOMMIT` to replace `OP_SUCCESS205` (0xcd). | ||||||||||||||
|
||||||||||||||
When evaluated, `OP_PAIRCOMMIT`: | ||||||||||||||
* Pops the top two values off the stack, | ||||||||||||||
* takes the "PairCommit" tagged SHA256 hash of the stack elements with size commitments, | ||||||||||||||
* pushes the resulting 32-byte hash to the top of stack. | ||||||||||||||
|
||||||||||||||
## Specification | ||||||||||||||
|
||||||||||||||
The notation below follows that of [BIP-340]. This includes the | ||||||||||||||
$$hash_{tag}(x)$$ notation to refer to | ||||||||||||||
$$SHA256(SHA256(tag) \\| SHA256(tag) \\| x)$$. | ||||||||||||||
|
||||||||||||||
* If fewer than 2 elements are on the stack, the script MUST fail and | ||||||||||||||
terminate immediately. | ||||||||||||||
* The top element ($$x2$$) and second to top element ($$x1$$) are read from the | ||||||||||||||
stack. | ||||||||||||||
* Let $$pc$$ be $$hash_{PairCommit}( | ||||||||||||||
compact\\_size(size\\:of\\:x1) \\| x1 \\| | ||||||||||||||
compact\\_size(size\\:of\\:x2) \\| x2)$$[^1] | ||||||||||||||
* The top two elements are popped from the stack. | ||||||||||||||
* $$pc$$ is pushed to the stack. | ||||||||||||||
|
||||||||||||||
[^1]: The number of SHA256 blocks is minimized in typical use cases. Since the | ||||||||||||||
Tag can be pre-computed as a SHA256 mid-state, it takes only 2 hash cycles | ||||||||||||||
for a commitment to 2 32-byte items or 1 for 2 smaller items. | ||||||||||||||
|
||||||||||||||
## Motivation | ||||||||||||||
|
||||||||||||||
Currently, bitcoin lacks a way to commit to multiple data items together. It | ||||||||||||||
is common practice to hash a single item as part of a bitcoin script. Either | ||||||||||||||
in hash/time locked contracts, or in pay-to-pubkey-hash (P2PKH) scripts, but | ||||||||||||||
there is no way to commit to multiple items with a single hash. | ||||||||||||||
|
||||||||||||||
With the ability to commit to pairs of elements, `OP_PAIRCOMMIT` can be | ||||||||||||||
generalized to Merklized commitments to a tree of elements with a single hash. | ||||||||||||||
On its own, this could enable a hash lock contract where the holder of any | ||||||||||||||
pre-image in a Merkle tree can unlock the spend, for example. | ||||||||||||||
|
||||||||||||||
If `OP_CHECKSIGFROMSTACK` is combined with `OP_PAIRCOMMIT`, the ability to sign | ||||||||||||||
commitments to multiple items enables complex delegation. For example, | ||||||||||||||
delegating to $$key1$$ after time $$t1$$ and $$key2$$ after time $$t2$$. | ||||||||||||||
Without `OP_PAIRCOMMIT` these complex delegations can be achieved using key | ||||||||||||||
laddering[^2], at a much greater validation cost. If the same key is simply | ||||||||||||||
used to sign multiple items, they can be combined arbitrarily, but | ||||||||||||||
`OP_PAIRCOMMIT` or key laddering[^2] enforces any desired relationships between | ||||||||||||||
(both sequence and combination) items. | ||||||||||||||
|
||||||||||||||
[^2]: `OP_CHECKSIGFROMSTACK` can commit to a sequence of otherwise | ||||||||||||||
undifferentiated items by requiring a key committed to by the output to | ||||||||||||||
sign an initial laddering key (`key0`) and then having `key0` sign a tuple | ||||||||||||||
of `(item1, key1)` and `key1` signing the tuple `(item2, key2)` etc. There | ||||||||||||||
are some details around ensuring that the items cannot be used as keys | ||||||||||||||
depending on the requirements of the protocol. This is costly both in | ||||||||||||||
bytes and sigops and `OP_PAIRCOMMIT` eliminates the need for such | ||||||||||||||
constructions when committing to any sequence of items. For details, see | ||||||||||||||
the [key laddering post] by Jeremy Rubin and Brandon Black. | ||||||||||||||
|
||||||||||||||
## Examples | ||||||||||||||
|
||||||||||||||
### Committing to more than 2 elements | ||||||||||||||
|
||||||||||||||
`OP_PAIRCOMMIT` can be used to commit to a vector of stack elements in a way | ||||||||||||||
that is not vulnerable to various forms of witness malleability. It is, however, | ||||||||||||||
highly optimized for just 2 stack elements. | ||||||||||||||
|
||||||||||||||
```text | ||||||||||||||
# pc-hash = PC(a, PC(b, c)) | ||||||||||||||
|
||||||||||||||
<a> <b> <c> | PC PC <pc-hash> OP_EQUALVERIFY | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
### Use in Lightning Symmetry | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think "LN-Symmetry" is more commonly used to refer to the concept than "Lightning Symmetry". Is there a specific reason why you prefer the latter? |
||||||||||||||
|
||||||||||||||
To create Lightning Symmetry contracts that neither require the nodes to keep | ||||||||||||||
old states nor require additional signing round trips (and corresponding | ||||||||||||||
signature validations), we need to solve a data availability problem presented | ||||||||||||||
by contested closes. Specifically, the second to act channel partner must be | ||||||||||||||
able to reconstruct the script that spends the first update transaction | ||||||||||||||
published. This script includes the hash of the corresponding settlement | ||||||||||||||
Comment on lines
+99
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is easier to parse:
Suggested change
|
||||||||||||||
transaction which we do not wish to store for all prior states. By having the | ||||||||||||||
channel and update state scripts force the parties to include the settlement | ||||||||||||||
transaction's hash in the witness to in order to publish the corresponding | ||||||||||||||
update transaction, then a later update can use the settlement hash from the | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m stumbling over this "in the witness to in order". Could you please revisit this sentence? |
||||||||||||||
first update transaction's witness to recreate the corresponding spend script. | ||||||||||||||
|
||||||||||||||
The following assembly-like pseudo-code shows a possible Lightning Symmetry | ||||||||||||||
channel construction that ensures sufficient data is available on chain in a | ||||||||||||||
force close to reconstruct the corresponding script and update it with a later | ||||||||||||||
state while only knowing the later state.[^3] The opcodes `OP_CHECKTEMPLATEVERIFY`, | ||||||||||||||
`OP_PAIRCOMMIT`, `OP_INTERNALKEY`, and `OP_CHECKSIGFROMSTACK` are abbreviated | ||||||||||||||
as `CTV`, `PC`, `IK`, and `CSFS` respectively. | ||||||||||||||
|
||||||||||||||
[^3]: Concretely the required data is a full CTV hash of the settlement | ||||||||||||||
transaction when there are open HTLCs, or merely the difference in balance | ||||||||||||||
between the channel partners in other cases. Whether the latter | ||||||||||||||
optimization would be used is an implementation detail not further | ||||||||||||||
discussed here. | ||||||||||||||
|
||||||||||||||
```text | ||||||||||||||
# S = 500000000 | ||||||||||||||
# internal key = [BIP-327] aggregate key of channel participants | ||||||||||||||
# channel script: | ||||||||||||||
<sig> <state-n-recovery-data> <state-n-hash> | CTV PC IK CSFS <S+1> CLTV DROP | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
Before funding, sign the first state. | ||||||||||||||
|
||||||||||||||
```text | ||||||||||||||
# state-n-hash { nLockTime(S+n), out(contract, amount(A)+amount(B)) } | ||||||||||||||
# settlement-n-hash { nSequence(2w), out(A, amount(A)), out(B, amount(B)) } | ||||||||||||||
# state-n-recovery-data { settlement-n-hash or state-n-balance } | ||||||||||||||
# update script: | ||||||||||||||
IF | ||||||||||||||
<sig> <state-m-recovery-data> <state-m-hash> | CTV PC IK CSFS <S+n+1> CLTV DROP | ||||||||||||||
ELSE | ||||||||||||||
<settlement-n-hash> CTV | ||||||||||||||
ENDIF | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
These scripts ensure the necessary data availability as follows: `CTV` commits | ||||||||||||||
to the update transaction's hash, `PC` combines this hash with the next stack | ||||||||||||||
item, and `CSFS` checks a MuSig 2-party signature against the resulting pair | ||||||||||||||
hash. Both parties must sign the same pair hash to produce a channel update, | ||||||||||||||
and they can therefore require each other to include both the update hash and | ||||||||||||||
settlement hash in the witness stack when initiating a force close. This | ||||||||||||||
Lightning Symmetry channel construction is close to [optimal]. | ||||||||||||||
|
||||||||||||||
### In MATT | ||||||||||||||
|
||||||||||||||
The Merklize All The Things ([MATT]) framework proposes to use `OP_CAT` to | ||||||||||||||
combine multiple items into a single commitment for use with | ||||||||||||||
`OP_CHECKCONTRACTVERIFY`. `OP_PAIRCOMMIT` provides a more ergonomic way to | ||||||||||||||
accomplish this[^4]. | ||||||||||||||
|
||||||||||||||
[^4]: `OP_CAT` can be used to commit to multiple items, but it is subject to | ||||||||||||||
byte shifting attacks if used naively. | ||||||||||||||
E.g. `0x0102 || 0x03` equals `0x01 || 0x0203`. Mitigating this correctly | ||||||||||||||
requires either length checking, hashing, or both. | ||||||||||||||
|
||||||||||||||
## Alternative approaches | ||||||||||||||
|
||||||||||||||
The following list of alternative approaches were discussed and rejected for | ||||||||||||||
various reasons, either for expanding the scope or for unnecessary complexity: | ||||||||||||||
|
||||||||||||||
* `OP_CAT`[^4][^7] | ||||||||||||||
* SHA256 streaming opcodes[^7] | ||||||||||||||
* Merkle operation opcodes | ||||||||||||||
* 'Kitty' CAT: `OP_CAT` with result or inputs arbitrarily limited in size | ||||||||||||||
* `OP_CHECKTEMPLATEVERIFY` committing to the taproot annex in tapscript[^5] | ||||||||||||||
* `OP_CHECKSIGFROMSTACK` on n elements as message | ||||||||||||||
* `OP_VECTORCOMMIT`: generalized form for n > 2 elements | ||||||||||||||
* ReKey/Laddering[^2] | ||||||||||||||
* `OP_RETURN`[^6] | ||||||||||||||
|
||||||||||||||
[^5]: As seen in Greg Sanders' [Lightning Symmetry write-up], one additional | ||||||||||||||
item can be committed to by a transaction signature by placing that item | ||||||||||||||
in the Taproot annex. This mechanism is limited to a single additional | ||||||||||||||
item and that item is not made accessible to script making it less useful. | ||||||||||||||
[^6]: `OP_RETURN` can also be used to cause a transaction signature or CTV | ||||||||||||||
hash to commit to additional data items. This is both costly for the user, | ||||||||||||||
as this inexpensive to validate data is pushed into transaction data | ||||||||||||||
instead of witness data and not accessible to script making it less useful | ||||||||||||||
like the annex. | ||||||||||||||
[^7]: `OP_PAIRCOMMIT` is intended to enable more useful bitcoin scripts, in | ||||||||||||||
some cases similar to those enabled by `OP_CAT` but without also enabling | ||||||||||||||
unexpected script behaviors such as those described by Andrew Poelstra in | ||||||||||||||
[CAT-tricks-I] and [CAT-tricks-II] or larger numeric operations. | ||||||||||||||
|
||||||||||||||
## Reference Implementation | ||||||||||||||
|
||||||||||||||
### Code | ||||||||||||||
|
||||||||||||||
```c++ | ||||||||||||||
case OP_PAIRCOMMIT: { | ||||||||||||||
// OP_PAIRCOMMIT is only available in Tapscript | ||||||||||||||
// ... | ||||||||||||||
// x1 x2 -- hash | ||||||||||||||
if (stack.size() < 2) { | ||||||||||||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); | ||||||||||||||
} | ||||||||||||||
const valtype& vch1 = stacktop(-2); | ||||||||||||||
const valtype& vch2 = stacktop(-1); | ||||||||||||||
|
||||||||||||||
uint256 hash = PairCommitHash(vch1, vch2); | ||||||||||||||
|
||||||||||||||
stack.pop_back(); | ||||||||||||||
stack.pop_back(); | ||||||||||||||
stack.emplace_back(hash.begin(), hash.end()); | ||||||||||||||
break; | ||||||||||||||
} | ||||||||||||||
``` | ||||||||||||||
```c++ | ||||||||||||||
const HashWriter HASHER_PAIRCOMMIT{TaggedHash("PairCommit")}; | ||||||||||||||
|
||||||||||||||
moonsettler marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
uint256 PairCommitHash(const std::vector<unsigned char>& x1, const std::vector<unsigned char>& x2) | ||||||||||||||
{ | ||||||||||||||
return (HashWriter{HASHER_PAIRCOMMIT} << x1 << x2).GetSHA256(); | ||||||||||||||
} | ||||||||||||||
``` | ||||||||||||||
|
||||||||||||||
### PR | ||||||||||||||
|
||||||||||||||
https://github.com/lnhance/bitcoin/pull/6/files | ||||||||||||||
|
||||||||||||||
## Rationale | ||||||||||||||
|
||||||||||||||
### Cost comparison of Lightning Symmetry constructions | ||||||||||||||
|
||||||||||||||
The following table briefly summarizes the costs associated with force closing | ||||||||||||||
Lightning Symmetry channels enabled by various combinations of proposed script | ||||||||||||||
upgrades. | ||||||||||||||
|
||||||||||||||
| Method | ChannelSc | UpdateSc | UpdateW | ForceC | Contest | Settle | | ||||||||||||||
| :--------------- | --------: | -------: | ------: | ------: | ------: | :----: | | ||||||||||||||
| APO-Annex | 8 WU | 113 WU | 100 WU | 1221 WU | 627 WU | SigOp | | ||||||||||||||
| APO-Return | 8 WU | 113 WU | 66 WU | 1359 WU | 765 WU | SigOp | | ||||||||||||||
| CTV+CSFS | 43 WU | 81 WU | 98 WU | 1394 WU | 765 WU | CTV | | ||||||||||||||
| CTV+CSFS+IKEY | 10 WU | 48 WU | 98 WU | 1328 WU | 732 WU | CTV | | ||||||||||||||
| CTV+CSFS+IKEY+PC | 11 WU | 49 WU | 131 WU | 1191 WU | 594 WU | CTV | | ||||||||||||||
|
||||||||||||||
*ChannelSc: channel script, UpdateSc: update script, UpdateW: witness is the | ||||||||||||||
same size for both Force Close and Contest in Lightning Symmetry, ForceC: total | ||||||||||||||
cost of unilateral close transactions, Contest: The additional cost to contest | ||||||||||||||
a force closure, Settle: Whether a signature operation or CTV operation is | ||||||||||||||
required to validate the settlement transaction* | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for expanding on the column titles. As I wrote above, it would be good to provide more context for this table. It would especially help if the compared schemata were at least briefly described and/or sources for details were provided. |
||||||||||||||
|
||||||||||||||
### Proving general computation using trees | ||||||||||||||
|
||||||||||||||
One potential risk of PAIRCOMMIT is that it may enable verification of general | ||||||||||||||
computations on bitcoin. | ||||||||||||||
|
||||||||||||||
Any script change which enables commitment to pairs of items necessarily | ||||||||||||||
enables commitments to Merkle trees. | ||||||||||||||
|
||||||||||||||
Merkle trees can be used to prove computation where the root of the tree | ||||||||||||||
represents the *function* and the leaves represent the *inputs* and *output*. | ||||||||||||||
There are practical limits to the total number of discrete output values that | ||||||||||||||
can be reached by all possible input values (i.e. the input entropy space) as | ||||||||||||||
they must be enumerated and hashed into a Merkle root. | ||||||||||||||
|
||||||||||||||
Taproot trees can be 128 levels deep, therefore including up to 2^128 possible | ||||||||||||||
output values. This is over the practical limits to enumerate and merklize. | ||||||||||||||
Therefore, we conclude that enabling Merkle commitments in script does not | ||||||||||||||
materially extend what computations are possible to validate in bitcoin | ||||||||||||||
script. While `OP_PAIRCOMMIT` is not explicitly limited to a height of 128, greater | ||||||||||||||
heights are not practical to Merklize. | ||||||||||||||
|
||||||||||||||
## Backward Compatibility | ||||||||||||||
|
||||||||||||||
By constraining the behavior of `OP_SUCCESS` opcodes, deployment of the BIP | ||||||||||||||
can be done in a backwards-compatible, soft-fork manner. If anyone were to | ||||||||||||||
rely on the `OP_SUCCESS` behavior of `OP_SUCCESS205`, `OP_PAIRCOMMIT` would | ||||||||||||||
invalidate their spend. | ||||||||||||||
|
||||||||||||||
## Deployment | ||||||||||||||
|
||||||||||||||
TBD | ||||||||||||||
|
||||||||||||||
## Credits | ||||||||||||||
|
||||||||||||||
Jeremy Rubin, Salvatore Ingala, Anthony Towns, Ademan555, Psifour | ||||||||||||||
|
||||||||||||||
## Copyright | ||||||||||||||
|
||||||||||||||
This document is licensed under the 3-clause BSD license. | ||||||||||||||
|
||||||||||||||
## References | ||||||||||||||
|
||||||||||||||
1. LNhance bitcoin repository: [lnhance] | ||||||||||||||
2. Lightning Symmetry: [eltoo] | ||||||||||||||
3. OP_CAT: [BIP-347], [BIN-2024-0001] | ||||||||||||||
4. OP_CHECKTEMPLATEVERIFY: [BIP-119] | ||||||||||||||
5. OP_CHECKSIGFROMSTACK: [BIP-348], [BIN-2024-0003] | ||||||||||||||
6. OP_INTERNALKEY: [BIP-349], [BIN-2024-0004] | ||||||||||||||
7. Tagged hash: [BIP-340] | ||||||||||||||
|
||||||||||||||
[lnhance]: https://github.com/lnhance/bitcoin | ||||||||||||||
[eltoo]: https://github.com/instagibbs/bolts/blob/eltoo_draft/XX-eltoo-transactions.md | ||||||||||||||
[CAT-tricks-I]: https://medium.com/blockstream/cat-and-schnorr-tricks-i-faf1b59bd298 | ||||||||||||||
[CAT-tricks-II]: https://medium.com/blockstream/cat-and-schnorr-tricks-ii-2f6ede3d7bb5 | ||||||||||||||
[MATT]: https://merkle.fun | ||||||||||||||
[Lightning Symmetry write-up]: https://delvingbitcoin.org/t/ln-symmetry-project-recap/359 | ||||||||||||||
[key laddering post]: https://rubin.io/bitcoin/2024/12/02/csfs-ctv-rekey-symmetry/ | ||||||||||||||
|
||||||||||||||
[//]: # (BIPs referenced) | ||||||||||||||
[BIP-119]: https://github.com/bitcoin/bips/tree/master/bip-0119.mediawiki | ||||||||||||||
[BIP-327]: https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki | ||||||||||||||
[BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki | ||||||||||||||
[BIP-347]: https://github.com/bitcoin/bips/blob/master/bip-0347.mediawiki | ||||||||||||||
[BIP-348]: https://github.com/bitcoin/bips/blob/master/bip-0348.md | ||||||||||||||
[BIP-349]: https://github.com/bitcoin/bips/blob/master/bip-0349.md | ||||||||||||||
[BIN-2024-0001]: https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0001.md | ||||||||||||||
[BIN-2024-0003]: https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0003.md | ||||||||||||||
[BIN-2024-0004]: https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0004.md | ||||||||||||||
|
||||||||||||||
[//]: # (Internal links) | ||||||||||||||
[optimal]: #cost-comparison-of-ln-symmetry-constructions | ||||||||||||||
|
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.
The sentence starting with "Either" seems to be missing one or more words.