Skip to content

Commit

Permalink
Add: PAIRCOMMIT
Browse files Browse the repository at this point in the history
  • Loading branch information
moonsettler committed Dec 28, 2024
1 parent 27e1394 commit 0ad3d24
Show file tree
Hide file tree
Showing 2 changed files with 272 additions and 0 deletions.
7 changes: 7 additions & 0 deletions README.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,13 @@ Those proposing changes should consider that ultimately consent may rest with th
| Gloria Zhao
| Informational
| Draft
|-
| [[bip-0442.md|442]]
| Consensus (soft fork)
| OP_PAIRCOMMIT
| moonsettler
| Standard
| Draft
|}

<!-- IMPORTANT! See the instructions at the top of this page, do NOT JUST add BIPs here! -->
265 changes: 265 additions & 0 deletions bip-0442.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
<pre>
BIP: 442
Layer: Consensus (soft fork)
Title: OP_PAIRCOMMIT
Author: moonsettler <[email protected]>
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0442
Status: Draft
Type: Standards Track
Created: 2024-12-09
License: BSD-3-Clause
</pre>

## 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 with size
commitments,
* pushes the resulting 32-byte hash to the top of stack.

## Motivation

Currently, bitcoin lacks a way to hash multiple stack elements together. Which
means building Merkle trees or verifying inclusion in a tree is not supported.

`OP_PAIRCOMMIT` is a simple and efficient tool to commit to two stack elements,
in a way that makes length redistribution attacks infeasible.

The number of SHA256 iterations is minimized in the typical use cases we can
optimize for. 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<unsigned char>& x1, const std::vector<unsigned char>& 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))
<a> <b> <c> | PC PC <pc-hash> OP_EQUALVERIFY
```

### Use in LN-Symmetry

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 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
<sig> <state-n-recovery-data> <state-n-hash> | CTV PC IK CSFS <S+1> CLTV DROP
```
before funding, sign the first state:
```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
<sig> <state-m-recovery-data> <state-m-hash> | CTV PC IK CSFS <S+n+1> CLTV DROP
ELSE
<settlement-n-hash> 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.

Using `OP_CAT` for this purpose requires additional opcodes to prevent witness
malleability (e.g. `0x0102 0x03 OP_CAT` is identical to `0x01 0x0203 OP_CAT`).

`OP_PAIRCOMMIT` solves this specific problem without introducing a wide range
of potentially controversial new behaviors like fully detailed introspection,
which includes the ability to inspect parent transactions and novel 2-way peg
mechanisms. ([CAT-tricks-I] and [CAT-tricks-II] by Andrew Poelstra)

Alternatively `OP_RETURN` could be used to ensure the availability of the state
recovery data, as `OP_CHECKTEMPLATEVERIFY` naturally commits to all outputs.
However, its cost in weight units would be over 4 times higher than that of
using `OP_PAIRCOMMIT`.

One way to think about the 3 opcodes (`OP_CHECKSIGFROMSTACK`, `OP_INTERNALKEY`,
`OP_PAIRCOMMIT`) is we decompose a `OP_CHECKSIGFROMSTACK` variant that can use
a 1-byte `OP_TRUE` public key (substituting for the *taproot internal key*) and
can commit to a number of stack elements as a message.

### Behaviors 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
* ReKey: key delegation and multiple use of OP_CHECKSIGFROMSTACK

### Cost comparison of LN-Symmetry constructions

| Method | ChannelSc | UpdateSc | UpdateW | ForceC | Contest | Settle |
| :------------ | --------: | -------: | ------: | ------: | ------: | :----: |
| APO-Annex | 8 WU | 113 WU | 100 WU | 1221 WU | 627 WU | SigOp |
| APO-Return | 8 WU | 113 WU | 66 WU | 1359 WU | 765 WU | SigOp |
| CTV+CSFS+IKEY | 10 WU | 48 WU | 98 WU | 1328 WU | 732 WU | CTV |
| CTV+CSFS | 43 WU | 81 WU | 98 WU | 1394 WU | 765 WU | CTV |
| LNhance | 11 WU | 49 WU | 131 WU | 1191 WU | 594 WU | CTV |

*ChannelSc: channel script, UpdateSc: update script, UpdateW: witness is the
same size for both Force Close and Contest in LN-Symmetry, ForceC: total cost of unilateral close transactions*

### Proving general computation

Merkle trees can be used to prove 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 they need
to be iterated over and hashed into a Merkle root.

Taproot MAST trees can currently cover 128 bits of entropy space, which is over
the practical limits to iterate over and merklize. Therefore, we conclude this
capability does not materially extend what computations are possible to prove
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 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
[CAT-tricks-I]: https://medium.com/blockstream/cat-and-schnorr-tricks-i-faf1b59bd298
[CAT-tricks-II]: https://medium.com/blockstream/cat-and-schnorr-tricks-ii-2f6ede3d7bb5

[//]: # (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)
[optimal]: #cost-comparison-of-ln-symmetry-constructions

0 comments on commit 0ad3d24

Please sign in to comment.