From 4838e6517552f5c3de9823afe57a550aa14aab5b Mon Sep 17 00:00:00 2001 From: moonsettler Date: Wed, 27 Nov 2024 19:54:43 +0100 Subject: [PATCH] Add: PAIRCOMMIT --- README.mediawiki | 7 ++ bip-PC.md | 220 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 bip-PC.md diff --git a/README.mediawiki b/README.mediawiki index 5adc1555c4..96d7fc6727 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -1274,6 +1274,13 @@ Those proposing changes should consider that ultimately consent may rest with th | Gloria Zhao | Informational | Draft +|- +| [[bip-PC.md|PC]] +| Consensus (soft fork) +| OP_PAIRCOMMIT +| moonsettler +| Standard +| Draft |} diff --git a/bip-PC.md b/bip-PC.md new file mode 100644 index 0000000000..61da48edff --- /dev/null +++ b/bip-PC.md @@ -0,0 +1,220 @@ +
+  BIP: ?
+  Layer: Consensus (soft fork)
+  Title: OP_PAIRCOMMIT
+  Author: moonsettler 
+  Comments-Summary: No comments yet.
+  Comments-URI: 
+  Status: Draft
+  Type: Standards Track
+  Created: 2024-11-08
+  License: BSD-3-CLAUSE
+
+ +## 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]( +#use-in-ln-symmetry) 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); + + popstack(stack); + popstack(stack); + 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 +``` +## 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. + +### 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 +[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.md +[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 \ No newline at end of file