-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
532c4c1
commit 4838e65
Showing
2 changed files
with
227 additions
and
0 deletions.
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
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,220 @@ | ||
<pre> | ||
BIP: ? | ||
Layer: Consensus (soft fork) | ||
Title: OP_PAIRCOMMIT | ||
Author: moonsettler <[email protected]> | ||
Comments-Summary: No comments yet. | ||
Comments-URI: <links to wiki page for comments> | ||
Status: Draft | ||
Type: Standards Track | ||
Created: 2024-11-08 | ||
License: BSD-3-CLAUSE | ||
</pre> | ||
|
||
## Abstract | ||
|
||
This BIP describes a new tapscript opcode `OP_PAIRCOMMIT` which | ||
provides limited vector commitment functionality in tapscript. | ||
|
||
When evaluated, the `OP_PAIRCOMMIT` instruction: | ||
* Pops the top two values off the stack, | ||
* takes the "PairCommit" tagged SHA256 hash of the stack elements, | ||
* pushes the resulting commitment on the top of the stack. | ||
|
||
## Motivation | ||
|
||
To do LN-Symmetry contracts that don't require the nodes to keep old states, | ||
we need to solve the data availability problem presented by unilateral closes. | ||
Channel peers must be able to reconstruct the script that spends an | ||
intermediate state. | ||
|
||
Using in sequence `OP_CHECKTEMPLATEVERIFY`, `OP_PAIRCOMMIT`, `OP_INTERNALKEY` | ||
and `OP_CHECKSIGFROMSTACK` we can construct a [rebindable channel]( | ||
#use-in-ln-symmetry) that is also optimal. | ||
|
||
The number of SHA256 iterations is minimized in the primary use case we | ||
can optimize for, which is LN-Symmetry. Since the Tag can be pre-computed as | ||
mid-state, it would only take 1 or 2 hash cycles in validation for the | ||
unilateral close scenario. | ||
|
||
## Specification | ||
|
||
Repurpose opcode 205 (currently `OP_SUCCESS`) as follows: | ||
|
||
`OP_PAIRCOMMIT` pops two elements off the stack, then concatenates them along | ||
with their size commitments and takes the tagged SHA256 hash of that | ||
concatenated string, then pushes the resulting hash back on the stack. | ||
|
||
Given the stack `[x1, x2]`, where `x2` is at the top of the stack: | ||
|
||
`OP_PAIRCOMMIT` will push `SHA256(tagPC|cs(x1)|x1|cs(x2)|x2)` onto the stack. | ||
|
||
Where `|` denotes concatenation and `tagPC` is calculated according to | ||
[BIP-340] tagged hash as `SHA256("PairCommit")|SHA256("PairCommit")` and | ||
`cs(x)` means `CompactSize(x)`. | ||
|
||
### Implementation | ||
|
||
```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); | ||
|
||
popstack(stack); | ||
popstack(stack); | ||
stack.emplace_back(hash.begin(), hash.end()); | ||
break; | ||
} | ||
``` | ||
```c++ | ||
const HashWriter HASHER_PAIRCOMMIT{TaggedHash("PairCommit")}; | ||
|
||
uint256 PairCommitHash(const std::vector<unsigned char>& x1, const std::vector<unsigned char>& x2) | ||
{ | ||
return (HashWriter{HASHER_PAIRCOMMIT} << x1 << x2).GetSHA256(); | ||
} | ||
``` | ||
### Use in script | ||
`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 LN-Symmetry | ||
|
||
The following assembly-like pseudo-code shows a possible LN-Symmetry channel | ||
construction, that provides data availability to spend to the latest state from | ||
an earlier state pushed on-chain with a forced close by channel partner. | ||
|
||
|
||
```text | ||
# S = 500000000 | ||
# IK -> A+B | ||
<sig> <state-n-recovery-data> <state-n-hash> | CTV PC IK CSFS <S+1> CLTV DROP | ||
``` | ||
before funding sign first state template: | ||
```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 } | ||
# contract for state n < m | ||
IF | ||
<sig> <state-m-recovery-data> <state-m-hash> | CTV PC IK CSFS <S+n+1> CLTV DROP | ||
ELSE | ||
<settlement-n-hash> CTV | ||
ENDIF | ||
``` | ||
## Reference Implementation | ||
|
||
A reference implementation is provided here: | ||
|
||
https://github.com/lnhance/bitcoin/pull/6/files | ||
|
||
## Rationale | ||
|
||
If `OP_CAT` was available, it could be used to combine multiple stack elements, | ||
that get verified with `OP_CHECKSIGFROMSTACK` as a valid state update. | ||
|
||
`OP_PAIRCOMMIT` solves this specific problem without introducing a wide range | ||
of potentially controversial new behaviors, such as novel 2-way peg mechanisms. | ||
|
||
`OP_RETURN` could also be used for ensuring the availability of the state | ||
recovery data as `OP_CHECKTEMPLATEVERIFY` naturally commits to all outputs. | ||
However the cost of that would be over 4 times higher in weight units. | ||
|
||
### Behaviours LNhance tries to avoid introducing | ||
|
||
The following behaviors are out of scope for LNhance and should not be enabled | ||
as a side effect without explicit consensus: | ||
|
||
* Fine grained introspection | ||
* State carrying covenants | ||
* Bigint operations | ||
* New arithmetic capabilities using lookup tables | ||
|
||
### 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 | ||
* SHA256 streaming opcodes | ||
* Merkle operation opcodes | ||
* 'Kitty' CAT: result or inputs arbitrarily limited in size | ||
* OP_CHECKTEMPLATEVERIFY committing to the taproot annex in tapscript | ||
* OP_CHECKSIGFROMSTACK on n elements as message | ||
* OP_VECTORCOMMIT: generalized form for n > 2 elements | ||
|
||
### Proving general computation | ||
|
||
Merkle trees can be used to prove out computation where the root of the tree | ||
represents the *function* and the leaves represent the *inputs* and *output*. | ||
There are practical limits to the entropy space for the *inputs* as it needs | ||
to be iterated over and hashed up. | ||
|
||
Currently MAST trees can cover 128 bits of entropy space, which is well over | ||
the practical limits to iterate over and merklize. Therefore we assume this | ||
capability does not materially extend what computations are possible to prove | ||
out in bitcoin script. While `OP_PAIRCOMMIT` is not limited to a height of 128, | ||
that should not be practically feasible to utilize. | ||
|
||
There is a way to reduce the size of the witness for proving out computation, | ||
by eliminating the merkle path inclusion proofs, using `OP_CHECKSIGFROMSTACK` | ||
together with `OP_PAIRCOMMIT`. This method involves deleted key assumptions, | ||
most likely using MPC to create an enormous amount of signatures for the stack | ||
elements representing the *inputs* and the *output* of the *function*. | ||
|
||
## 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, Brandon Black, Salvatore Ingala, Anthony Towns, Ademan555 | ||
|
||
## Copyright | ||
|
||
This document is licensed under the 3-clause BSD license. | ||
|
||
## References | ||
|
||
1. LNhance bitcoin repository: [lnhance] | ||
2. LN-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 | ||
[BIP-119]: https://github.com/bitcoin/bips/tree/master/bip-0119.mediawiki | ||
[BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki | ||
[BIP-347]: https://github.com/bitcoin/bips/blob/master/bip-0347.md | ||
[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 |