-
Notifications
You must be signed in to change notification settings - Fork 8
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
OP_PAIRCOMMIT #8
Open
moonsettler
wants to merge
5
commits into
bitcoin-inquisition:master
Choose a base branch
from
moonsettler:pc
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
5 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,161 @@ | ||
| BIN-2024-006 | `OP_PAIRCOMMIT` | ||
| :------------ | :------- | ||
| Revision | 006 (2024-11-08) | ||
| Author | moonsettler `<[email protected]>` | ||
| | | ||
| Layer | Consensus (soft fork) | ||
| Status | Draft | ||
| License | BSD-3-CLAUSE | ||
| | | ||
| Discussion | [https://delvingbitcoin.org/t/op-paircommit-as-a-candidate-for-addition-to-lnhance/1216/12] | ||
| Aliases | [BIPs PR#????](https://github.com/bitcoin/bips/pull/?) | ||
|
||
## Abstract | ||
|
||
This BIP describes a new tapscript opcode `OP_PAIRCOMMIT` which | ||
provide 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 that is also | ||
optimal. | ||
|
||
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. | ||
|
||
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 | ||
``` | ||
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 these are LN-Symmetry specific examples? There's not really enough context to follow them here though, and I would have thought they'd make more sense in a separate LN/LNHANCE-Symmetry BOLT? |
||
|
||
## Reference Implementation | ||
|
||
A reference implementation is provided here: | ||
|
||
[https://github.com/lnhance/bitcoin/pull/6/files] | ||
|
||
## 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. | ||
moonsettler marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Deployment | ||
|
||
TBD | ||
|
||
## Credits | ||
|
||
Jeremy Rubin, Brandon Black, Salvatore Ingala, Anthony Towns | ||
|
||
## Copyright | ||
|
||
This document is licensed under the 3-clause BSD license. | ||
|
||
## References | ||
|
||
1. LNhance bitcoin repository ["LNhance"](https://github.com/lnhance/bitcoin) | ||
2. LN-Symmetry ["eltoo"](https://github.com/instagibbs/bolts/blob/eltoo_draft/XX-eltoo-transactions.md) | ||
3. OP_CAT, ["BIN-2024-0001"](https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0001.md) | ||
4. OP_CHECKTEMPLATEVERIFY, ["BIP 119"](https://github.com/bitcoin/bips/tree/master/bip-0119) | ||
5. OP_CHECKSIGFROMSTACK, ["BIN-2024-0003"](https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0003.md) | ||
6. OP_INTERNALKEY, ["BIN-2024-0004"](https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0004.md) | ||
7. Tagged hash, ["BIP-340"](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) |
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
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.
Correct me if I'm wrong but shouldn't this be
PC(PC(c, b), a)
If the stack is
c
b
a
And
PC(PC(a, b), c)
If the stack is
a
b
c
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.
PC takes the top element as vch2 and the one below the top as vch1. Then pushes PC(vch1, vch2) on stack.
It should be
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.
Ohh I see I had misread the code, this makes sense now thanks for clearing it up!
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.
Here are the unit tests, you can execute PC only if you check out that branch, build it and run
pchash_reproduce
on line 68 shows you how to manually reproduce the output, andpchash_tapscript
shows you how you can give it a spin in the interpreter.https://github.com/lnhance/bitcoin/blob/lnhance-26.x/src/test/pchash_tests.cpp