Skip to content

Commit 0ad3d24

Browse files
committed
Add: PAIRCOMMIT
1 parent 27e1394 commit 0ad3d24

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed

README.mediawiki

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,13 @@ Those proposing changes should consider that ultimately consent may rest with th
12881288
| Gloria Zhao
12891289
| Informational
12901290
| Draft
1291+
|-
1292+
| [[bip-0442.md|442]]
1293+
| Consensus (soft fork)
1294+
| OP_PAIRCOMMIT
1295+
| moonsettler
1296+
| Standard
1297+
| Draft
12911298
|}
12921299

12931300
<!-- IMPORTANT! See the instructions at the top of this page, do NOT JUST add BIPs here! -->

bip-0442.md

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
<pre>
2+
BIP: 442
3+
Layer: Consensus (soft fork)
4+
Title: OP_PAIRCOMMIT
5+
Author: moonsettler <[email protected]>
6+
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0442
7+
Status: Draft
8+
Type: Standards Track
9+
Created: 2024-12-09
10+
License: BSD-3-Clause
11+
</pre>
12+
13+
## Abstract
14+
15+
This BIP describes a new tapscript opcode `OP_PAIRCOMMIT`, which
16+
provides limited vector commitment functionality in tapscript.
17+
18+
When evaluated, the `OP_PAIRCOMMIT` instruction:
19+
* Pops the top two values off the stack,
20+
* takes the "PairCommit" tagged SHA256 hash of the stack elements with size
21+
commitments,
22+
* pushes the resulting 32-byte hash to the top of stack.
23+
24+
## Motivation
25+
26+
Currently, bitcoin lacks a way to hash multiple stack elements together. Which
27+
means building Merkle trees or verifying inclusion in a tree is not supported.
28+
29+
`OP_PAIRCOMMIT` is a simple and efficient tool to commit to two stack elements,
30+
in a way that makes length redistribution attacks infeasible.
31+
32+
The number of SHA256 iterations is minimized in the typical use cases we can
33+
optimize for. Since the Tag can be pre-computed as mid-state, it would only
34+
take 1 or 2 hash cycles in validation for the unilateral close scenario.
35+
36+
## Specification
37+
38+
Repurpose opcode 205 (currently `OP_SUCCESS`) as follows:
39+
40+
`OP_PAIRCOMMIT` pops two elements off the stack, then concatenates them along
41+
with their size commitments and takes the tagged SHA256 hash of that
42+
concatenated string, then pushes the resulting hash back on the stack.
43+
44+
Given the stack `[x1, x2]`, where `x2` is at the top of the stack:
45+
46+
`OP_PAIRCOMMIT` will push `SHA256(tagPC|cs(x1)|x1|cs(x2)|x2)` onto the stack.
47+
48+
Where `|` denotes concatenation and `tagPC` is calculated according to
49+
[BIP-340] tagged hash as `SHA256("PairCommit")|SHA256("PairCommit")` and
50+
`cs(x)` means `CompactSize(x)`.
51+
52+
### Implementation
53+
54+
```c++
55+
case OP_PAIRCOMMIT: {
56+
// OP_PAIRCOMMIT is only available in Tapscript
57+
// ...
58+
// x1 x2 -- hash
59+
if (stack.size() < 2) {
60+
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
61+
}
62+
const valtype& vch1 = stacktop(-2);
63+
const valtype& vch2 = stacktop(-1);
64+
65+
uint256 hash = PairCommitHash(vch1, vch2);
66+
67+
stack.pop_back();
68+
stack.pop_back();
69+
stack.emplace_back(hash.begin(), hash.end());
70+
break;
71+
}
72+
```
73+
```c++
74+
const HashWriter HASHER_PAIRCOMMIT{TaggedHash("PairCommit")};
75+
76+
uint256 PairCommitHash(const std::vector<unsigned char>& x1, const std::vector<unsigned char>& x2)
77+
{
78+
return (HashWriter{HASHER_PAIRCOMMIT} << x1 << x2).GetSHA256();
79+
}
80+
```
81+
### Use in script
82+
83+
`OP_PAIRCOMMIT` can be used to commit to a vector of stack elements in a way
84+
that is not vulnerable to various forms of witness malleability. It is, however,
85+
highly optimized for just 2 stack elements.
86+
87+
```text
88+
# pc-hash = PC(a, PC(b, c))
89+
90+
<a> <b> <c> | PC PC <pc-hash> OP_EQUALVERIFY
91+
```
92+
93+
### Use in LN-Symmetry
94+
95+
To do LN-Symmetry contracts that don't require the nodes to keep old states,
96+
we need to solve the data availability problem presented by unilateral closes.
97+
Channel peers must be able to reconstruct the script that spends an
98+
intermediate state.
99+
100+
Using in sequence `OP_CHECKTEMPLATEVERIFY`, `OP_PAIRCOMMIT`, `OP_INTERNALKEY`
101+
and `OP_CHECKSIGFROMSTACK` we can construct a rebindable channel that is also
102+
[optimal].
103+
104+
The following assembly-like pseudo-code shows a possible LN-Symmetry channel
105+
construction that provides data availability to spend to the latest state from
106+
an earlier state pushed on-chain with a forced close by channel partner.
107+
108+
109+
```text
110+
# S = 500000000
111+
# IK -> A+B
112+
<sig> <state-n-recovery-data> <state-n-hash> | CTV PC IK CSFS <S+1> CLTV DROP
113+
```
114+
before funding, sign the first state:
115+
```text
116+
# state-n-hash { nLockTime(S+n), out(contract, amount(A)+amount(B)) }
117+
# settlement-n-hash { nSequence(2w), out(A, amount(A)), out(B, amount(B)) }
118+
# state-n-recovery-data { settlement-n-hash or state-n-balance }
119+
120+
# contract for state n < m
121+
IF
122+
<sig> <state-m-recovery-data> <state-m-hash> | CTV PC IK CSFS <S+n+1> CLTV DROP
123+
ELSE
124+
<settlement-n-hash> CTV
125+
ENDIF
126+
```
127+
128+
### Use with future updates
129+
130+
Detailed introspection opcodes would also need vector commitments when used
131+
with `OP_CHECKSIGFROMSTACK`.
132+
133+
`OP_CHECKCONTRACTVERIFY` would also need a way to carry complex data.
134+
135+
## Reference Implementation
136+
137+
A reference implementation is provided here:
138+
139+
https://github.com/lnhance/bitcoin/pull/6/files
140+
141+
## Rationale
142+
143+
If `OP_CAT` was available, it could be used to combine multiple stack elements
144+
that get verified with `OP_CHECKSIGFROMSTACK` as a valid state update.
145+
146+
Using `OP_CAT` for this purpose requires additional opcodes to prevent witness
147+
malleability (e.g. `0x0102 0x03 OP_CAT` is identical to `0x01 0x0203 OP_CAT`).
148+
149+
`OP_PAIRCOMMIT` solves this specific problem without introducing a wide range
150+
of potentially controversial new behaviors like fully detailed introspection,
151+
which includes the ability to inspect parent transactions and novel 2-way peg
152+
mechanisms. ([CAT-tricks-I] and [CAT-tricks-II] by Andrew Poelstra)
153+
154+
Alternatively `OP_RETURN` could be used to ensure the availability of the state
155+
recovery data, as `OP_CHECKTEMPLATEVERIFY` naturally commits to all outputs.
156+
However, its cost in weight units would be over 4 times higher than that of
157+
using `OP_PAIRCOMMIT`.
158+
159+
One way to think about the 3 opcodes (`OP_CHECKSIGFROMSTACK`, `OP_INTERNALKEY`,
160+
`OP_PAIRCOMMIT`) is we decompose a `OP_CHECKSIGFROMSTACK` variant that can use
161+
a 1-byte `OP_TRUE` public key (substituting for the *taproot internal key*) and
162+
can commit to a number of stack elements as a message.
163+
164+
### Behaviors LNhance tries to avoid introducing
165+
166+
The following behaviors are out of scope for LNhance and should not be enabled
167+
as a side effect without explicit consensus:
168+
169+
* Fine-grained introspection
170+
* State-carrying covenants
171+
* Bigint operations
172+
* New arithmetic capabilities using lookup tables
173+
174+
### Alternative approaches
175+
176+
The following list of alternative approaches were discussed and rejected for
177+
various reasons, either for expanding the scope or for unnecessary complexity:
178+
179+
* OP_CAT
180+
* SHA256 streaming opcodes
181+
* Merkle operation opcodes
182+
* 'Kitty' CAT: result or inputs arbitrarily limited in size
183+
* OP_CHECKTEMPLATEVERIFY committing to the taproot annex in tapscript
184+
* OP_CHECKSIGFROMSTACK on n elements as message
185+
* OP_VECTORCOMMIT: generalized form for n > 2 elements
186+
* ReKey: key delegation and multiple use of OP_CHECKSIGFROMSTACK
187+
188+
### Cost comparison of LN-Symmetry constructions
189+
190+
| Method | ChannelSc | UpdateSc | UpdateW | ForceC | Contest | Settle |
191+
| :------------ | --------: | -------: | ------: | ------: | ------: | :----: |
192+
| APO-Annex | 8 WU | 113 WU | 100 WU | 1221 WU | 627 WU | SigOp |
193+
| APO-Return | 8 WU | 113 WU | 66 WU | 1359 WU | 765 WU | SigOp |
194+
| CTV+CSFS+IKEY | 10 WU | 48 WU | 98 WU | 1328 WU | 732 WU | CTV |
195+
| CTV+CSFS | 43 WU | 81 WU | 98 WU | 1394 WU | 765 WU | CTV |
196+
| LNhance | 11 WU | 49 WU | 131 WU | 1191 WU | 594 WU | CTV |
197+
198+
*ChannelSc: channel script, UpdateSc: update script, UpdateW: witness is the
199+
same size for both Force Close and Contest in LN-Symmetry, ForceC: total cost of unilateral close transactions*
200+
201+
### Proving general computation
202+
203+
Merkle trees can be used to prove computation where the root of the tree
204+
represents the *function* and the leaves represent the *inputs* and *output*.
205+
There are practical limits to the entropy space for the *inputs* as they need
206+
to be iterated over and hashed into a Merkle root.
207+
208+
Taproot MAST trees can currently cover 128 bits of entropy space, which is over
209+
the practical limits to iterate over and merklize. Therefore, we conclude this
210+
capability does not materially extend what computations are possible to prove
211+
in bitcoin script. While `OP_PAIRCOMMIT` is not limited to a height of 128,
212+
that should not be practically feasible to utilize.
213+
214+
There is a way to reduce the size of the witness for proving computation,
215+
by eliminating the Merkle path inclusion proofs, using `OP_CHECKSIGFROMSTACK`
216+
together with `OP_PAIRCOMMIT`. This method involves deleted key assumptions,
217+
most likely using MPC to create an enormous amount of signatures for the stack
218+
elements representing the *inputs* and the *output* of the *function*.
219+
220+
## Backward Compatibility
221+
222+
By constraining the behavior of OP_SUCCESS opcodes, deployment of the BIP
223+
can be done in a backwards-compatible, soft-fork manner. If anyone were to
224+
rely on the OP_SUCCESS behavior of `OP_SUCCESS205`, `OP_PAIRCOMMIT` would
225+
invalidate their spend.
226+
227+
## Deployment
228+
229+
TBD
230+
231+
## Credits
232+
233+
Jeremy Rubin, Brandon Black, Salvatore Ingala, Anthony Towns, Ademan555
234+
235+
## Copyright
236+
237+
This document is licensed under the 3-clause BSD license.
238+
239+
## References
240+
241+
1. LNhance bitcoin repository: [lnhance]
242+
2. LN-Symmetry: [eltoo]
243+
3. OP_CAT: [BIP-347], [BIN-2024-0001]
244+
4. OP_CHECKTEMPLATEVERIFY: [BIP-119]
245+
5. OP_CHECKSIGFROMSTACK: [BIP-348], [BIN-2024-0003]
246+
6. OP_INTERNALKEY: [BIP-349], [BIN-2024-0004]
247+
7. Tagged hash: [BIP-340]
248+
249+
[lnhance]: https://github.com/lnhance/bitcoin
250+
[eltoo]: https://github.com/instagibbs/bolts/blob/eltoo_draft/XX-eltoo-transactions.md
251+
[CAT-tricks-I]: https://medium.com/blockstream/cat-and-schnorr-tricks-i-faf1b59bd298
252+
[CAT-tricks-II]: https://medium.com/blockstream/cat-and-schnorr-tricks-ii-2f6ede3d7bb5
253+
254+
[//]: # (BIPs referenced)
255+
[BIP-119]: https://github.com/bitcoin/bips/tree/master/bip-0119.mediawiki
256+
[BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
257+
[BIP-347]: https://github.com/bitcoin/bips/blob/master/bip-0347.mediawiki
258+
[BIP-348]: https://github.com/bitcoin/bips/blob/master/bip-0348.md
259+
[BIP-349]: https://github.com/bitcoin/bips/blob/master/bip-0349.md
260+
[BIN-2024-0001]: https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0001.md
261+
[BIN-2024-0003]: https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0003.md
262+
[BIN-2024-0004]: https://github.com/bitcoin-inquisition/binana/blob/master/2024/BIN-2024-0004.md
263+
264+
[//]: # (Internal links)
265+
[optimal]: #cost-comparison-of-ln-symmetry-constructions

0 commit comments

Comments
 (0)