|
| 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