diff --git a/2024/BIN-2024-0006.md b/2024/BIN-2024-0006.md new file mode 100644 index 0000000..3fe7be1 --- /dev/null +++ b/2024/BIN-2024-0006.md @@ -0,0 +1,238 @@ +| BIN-2024-006 | `OP_PAIRCOMMIT` +| :------------ | :------- +| Revision | 010 (2024-12-03) +| Author | moonsettler `` +| | +| Layer | Consensus (soft fork) +| Status | Draft +| License | BSD-3-CLAUSE +| | +| Discussion | [delvingbitcoin](https://delvingbitcoin.org/t/op-paircommit-as-a-candidate-for-addition-to-lnhance/1216/12) +| Aliases | [BIPs PR#1699](https://github.com/bitcoin/bips/pull/1699) + +## 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] 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); + + stack.pop_back(); + stack.pop_back(); + stack.emplace_back(hash.begin(), hash.end()); + break; +} +``` +```c++ +const HashWriter HASHER_PAIRCOMMIT{TaggedHash("PairCommit")}; + +uint256 PairCommitHash(const std::vector& x1, const std::vector& 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)) + + | PC PC 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 + | CTV PC IK CSFS 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 + | CTV PC IK CSFS CLTV DROP +ELSE + CTV +ENDIF +``` + +### Use with future updates + +Detailed introspection opcodes would also need vector commitments when used +with `OP_CHECKSIGFROMSTACK`. + +`OP_CHECKCONTRACTVERIFY` would also need a way to carry complex data. + +## 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. + +One way to think about the 3 opcodes (`OP_CHECKSIGFROMSTACK`, `OP_INTERNALKEY`, +`OP_PAIRCOMMIT`) is we decompose a `OP_CHECKSIGFROMSTACK` variant that can use +1 byte `OP_TRUE` public key (substitute for the *taproot internal key*) and can +commit to a number of stack elements as message. + +### 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 + +[//]: # (BIPs referenced) +[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.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) +[LN-Symmetry]: #use-in-ln-symmetry +[rebindable channel]: #use-in-ln-symmetry \ No newline at end of file diff --git a/README.md b/README.md index 72682fe..1cc827b 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ may be identified by appending ".RRR", the three digit revision number. | BIN-2024-0003 | Draft | [`CHECKSIGFROMSTACK`](2024/BIN-2024-0003.md) | BIN-2024-0004 | Draft | [`OP_INTERNALKEY`](2024/BIN-2024-0004.md) | BIN-2024-0005 | Info | [Bitcoin Related Specifications](2024/BIN-2024-0005.md) +| BIN-2024-0006 | Draft | [`OP_PAIRCOMMIT`](2024/BIN-2024-0006.md) ## Notes