Hi All, We propose to add a new opcode to tapscript, the newest member of the LNhance opcode family, OP_PAIRCOMMIT. LNhance is a package deal of CTV + CSFS + IKEY + PC specifically designed to enable efficient rebindable channels, that can be grafted to a variety ofcovenant tree / channel factory constructions. 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. https://gist.github.com/moonsettler/d7f1fb88e3e54ee7ecb6d69ff126433b PR: 1699 to https://github.com/bitcoin/bips Q: Why not CAT? A: OP_PAIRCOMMIT was specifically introduced so that we don't have a dependency on CAT for efficient LN-Symmetry construction. If we already had CAT or had reasonable assurances that CAT will be activated soon, the balance of tradeoffs might have tipped against a late introduction of a new opcode to a concept that was already floating out there. Q: What is the difference between PAIRCOMMIT and CAT? A: PAIRCOMMIT is domain separated from other implicit uses of hashing pieces of data together. CAT allows for reconstructing and therefore inspecting sighashes on the stack. And not only it allows for fine grained introspection, it also allows for inspecting ancestor transactions. This makes CAT with the Poelstra trick a way to implement state carrying covenants. * If CAT has consensus, PAIRCOMMIT is an optimization of which we already have plenty examples of in script * If CAT has no consensus, PAIRCOMMIT gets the job done in regards to a veryspecific subset of behaviors, that explicitly do not include introspection. BR. moonsettler --------------------------------------------------------------------------------
BIP: ? Layer: Consensus (soft fork) Title: OP_PAIRCOMMIT Author: moonsettler < moonsettler@protonmail.com > Comments-Summary: No comments yet. Comments-URI:## 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::vectorStatus: Draft Type: Standards Track Created: 2024-11-08 License: BSD-3-CLAUSE