OP_PAIRCOMMIT #1699

pull moonsettler wants to merge 6 commits into bitcoin:master from lnhance:paircommit changing 2 files +258 −0
  1. moonsettler commented at 11:07 pm on November 11, 2024: contributor

    OP_PAIRCOMMIT is the newest member of the LNhance family of opcodes. It 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.

    Discussion: https://delvingbitcoin.org/t/op-paircommit-as-a-candidate-for-addition-to-lnhance/1216/12

  2. murchandamus commented at 4:32 pm on November 13, 2024: contributor

    This document has a few formatting issues, please make sure that the preamble matches the BIP 2 requirements and take a look at the rich diff to see whether it looks the way you intend.

    Please note that the BIPs repository also accepts markdown files.

  3. moonsettler commented at 8:16 pm on November 13, 2024: contributor
    Switched back to markdown. Header now in BIP-2 format.
  4. moonsettler force-pushed on Nov 13, 2024
  5. moonsettler force-pushed on Nov 13, 2024
  6. moonsettler commented at 9:49 pm on November 13, 2024: contributor
    The original create date of OP_PAIRCOMMIT is 2024-03-15 this is the latest revision based on feedback from Anthony Towns. https://gist.github.com/moonsettler/d7f1fb88e3e54ee7ecb6d69ff126433b/revisions What date should go to the header?
  7. jonatack commented at 2:39 am on November 14, 2024: member

    Added a discussion link to the PR description.

    The original create date of OP_PAIRCOMMIT is 2024-03-15 this is the latest revision based on feedback from Anthony Towns. gist.github.com/moonsettler/d7f1fb88e3e54ee7ecb6d69ff126433b/revisions What date should go to the header?

    Perhaps add a changelog with the revision based on Anthony Towns’ feedback followed by the initial version. Or use the date of the current draft revision as your starting point.

  8. jonatack added the label New BIP on Nov 14, 2024
  9. murchandamus commented at 3:51 pm on November 14, 2024: contributor

    According to BIP 2:

    The Created header records the date that the BIP was assigned a number, […]

  10. moonsettler marked this as ready for review on Nov 14, 2024
  11. murchandamus commented at 10:10 pm on November 14, 2024: contributor
    Has this proposal been sent to the mailing list?
  12. moonsettler commented at 10:16 pm on November 14, 2024: contributor

    Has this proposal been sent to the mailing list?

    Not yet. Wanted to get it into an acceptable shape before I post it there.

    Proposed to the mailing list, waiting for feedback.

  13. in README.mediawiki:1270 in 08ffb0303d outdated
    1266@@ -1267,6 +1267,13 @@ Those proposing changes should consider that ultimately consent may rest with th
    1267 | Gloria Zhao
    1268 | Informational
    1269 | Draft
    1270+|- style="background-color: #cfffcf"
    


    murchandamus commented at 3:15 pm on November 15, 2024:

    For Draft status PRs the background color is not specified

    0|-
    
  14. in README.mediawiki:1273 in 08ffb0303d outdated
    1266@@ -1267,6 +1267,13 @@ Those proposing changes should consider that ultimately consent may rest with th
    1267 | Gloria Zhao
    1268 | Informational
    1269 | Draft
    1270+|- style="background-color: #cfffcf"
    1271+| [[bip-PC.md|PC]]
    1272+| Consensus (soft fork)
    1273+| PAIRCOMMIT
    


    murchandamus commented at 3:15 pm on November 15, 2024:

    This has to match the title header in the preamble:

    0| OP_PAIRCOMMIT
    
  15. in bip-PC.md:39 in 08ffb0303d outdated
    34+
    35+If `OP_CAT` was available, it could be used to combine multiple stack elements,
    36+that get verified with `OP_CHECKSIGFROMSTACK` as a valid state update.
    37+
    38+`OP_PAIRCOMMIT` solves this specific problem without introducing a wide range
    39+of potentially controversial new behaviors, such as novel 2-way peg mechanisms.
    


    murchandamus commented at 3:17 pm on November 15, 2024:
    It sounds like OP_PAIRCOMMIT is closely related to CAT and CSFS. Could you perhaps expand on the related work and design decisions in a Rationale section?

    moonsettler commented at 3:44 pm on November 15, 2024:

    Alternatives we discussed:

    • OP_CAT
    • Merkle operation opcodes
    • SHA256 streaming opcodes
    • ‘Kitty’ CAT (result or inputs limited in size to try disable introspection and arithmetic extension uses)
    • OP_CTV also commiting to the taproot annex in tapscript
    • OP_CHECKSIGFROMSTACK variant on n elements as message instead of 1
    • OP_VECTORCOMMIT (decoupling above behavior)

    Finally after weighing everything OP_PAIRCOMMIT was the simplest addition that got what we needed exactly in the most efficient way. It’s a minimal code change, very easy to reason about. Therefore we expect it to be the least controversial option.

    Sadly a lot of the discussion is all over the place and on unsearchable mediums.


    murchandamus commented at 9:45 pm on November 15, 2024:
    That’s why I am suggesting that this proposal should collect some of that information.

    moonsettler commented at 10:14 pm on November 15, 2024:
    I would prefer to keep it simple and to the point. Added a more brief rationale section. Could do a more in depth recollection on what we learned and why certain alternatives fell out of favor on a delving thread we link from here, if people are actually curious.

    moonsettler commented at 3:46 pm on November 23, 2024:
    Expanded on the rationale behind OP_PAIRCOMMIT on delvingbitcoin.
  16. in bip-PC.md:127 in 40f0b0f3e4 outdated
    129+## Reference Implementation
    130+
    131+A reference implementation is provided here:
    132+
    133+https://github.com/lnhance/bitcoin/pull/6/files
    134+
    


    moonsettler commented at 4:30 pm on November 15, 2024:

    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.

    Alternatives discussed

    • OP_CAT

    OP_CAT allows for fine grained introspection possibly bigint operations and extending the arithmetic capabilities of bitcoin script using lookup tables.

    • SHA256 streaming opcodes

    These would predictably allow for the same functionality as OP_CAT for introspection purposes, since verification of a computation is largely equivalent with carrying it out. Bigint and new arithmetic operations would be hard or even impossible.

    • Merkle operation opcodes

    These would be of very limited general use and hard to rationalize without OP_CAT. Their complexity and resource cost is hard to justified for vector commitments only. Compatibility considerations with taproot MAST were also hard to resolve without knowing what other opcodes may be activated in the future.

    • ‘Kitty’ CAT (result or inputs limited in size)

    The original idea would have limited the maximum size of OP_CAT output to a size that is smaller than the smallest sighash preimage, thus disabling the introspection capabilities and trivial ways to extend the arithmetic repertoir of bitcoin script. This turned out to be an awkward, arbitrary and offering weak .

    • OP_CHECKTEMPLATEVERIFY commiting to the taproot annex in tapscript

    A CTV template can be considered a sighash, however relaxing the relay policy to take advantage of this change would make various endogenous asset protocols more efficient, and therefore be controversial. There is also no consensus on how to use or how to structure the annex.

    • OP_CHECKSIGFROMSTACK on n elements as message

    This was previosuly discussed and also implemented, it complicates the code and is a pretty arbitrary coupling of behaviors.

    • OP_VECTORCOMMIT

    The obvious generalized solution for committing to n stack elements, however it involves looping and hard to argue about setting the proper limits to it.

  17. moonsettler force-pushed on Nov 15, 2024
  18. moonsettler force-pushed on Nov 15, 2024
  19. moonsettler force-pushed on Nov 15, 2024
  20. moonsettler force-pushed on Nov 23, 2024
  21. in bip-PC.md:17 in 92ffeb88fb outdated
    12+</pre>
    13+
    14+## Abstract
    15+
    16+This BIP describes a new tapscript opcode `OP_PAIRCOMMIT` which
    17+provide limited vector commitment functionality in tapscript.
    


    murchandamus commented at 4:01 pm on November 25, 2024:
    0provides limited vector commitment functionality in tapscript.
    
  22. in bip-PC.md:33 in 92ffeb88fb outdated
    28+Channel peers must be able to reconstruct the script that spends an
    29+intermediate state.
    30+
    31+Using in sequence `OP_CHECKTEMPLATEVERIFY`, `OP_PAIRCOMMIT`, `OP_INTERNALKEY`
    32+and `OP_CHECKSIGFROMSTACK` we can construct a rebindable channel that is also
    33+optimal.
    


    murchandamus commented at 4:02 pm on November 25, 2024:
    This paragraph seems to indicate that the OP_PAIRCOMMIT proposal would be especially useful in combination with these other opcodes. Could you perhaps clarify whether and how OP_PAIRCOMMIT is useful by itself in absence of the other three opcodes you mention here?

    moonsettler commented at 4:43 pm on November 25, 2024:

    LNhance at it’s core is CTV + CSFS. They together provide the core utility. IKEY is an optimization for not having to pay for the pubkey twice when the internal key can be used. PC is an optimization when CSFS has to commit to additional data required to recreate a spend script from an intermediate state, because OP_RETURN (to which CTV naturally commits to) is 4x more expensive in weight units for data availability.

    PC could also be used by CHECKCONTRACTVERIFY to carry a complex state in the absence of CAT.

    I don’t think anyone would find PC useful enough to activate in isolation without the aforementioned other opcodes. It can do general merkle tree style commitments that are not compatible with other merkle tree structures in bitcoin.

    We probably will make a new BIP for LNhance that has these other BIPs as “Relies on”.


    murchandamus commented at 1:25 pm on November 26, 2024:
    I meant that these explanations should be part of the BIP, not just part of the conversation here in the pull request comments.

    moonsettler commented at 1:58 pm on November 26, 2024:
    So should I link the “Use in LN-Symmetry” section from there? Or it needs better explanation?

    moonsettler commented at 2:02 pm on November 26, 2024:

    Really leaning towards making a head BIP for LNhance and keeping the individual BIPs strictly limited to describing functionality without a lot of speculation on applications. (Which we would do after finalizing the individual ops.)

    Is there a problem with this approach?


    murchandamus commented at 2:26 pm on November 26, 2024:
    If you are creating multiple BIPs that only make sense together, it would be better to propose them as a single pull request. Since this is being proposed standalone, it should also provide its own raison d’être.

    moonsettler commented at 2:51 pm on November 26, 2024:
    Maybe I should write that it was an explicit design goal that PAIRCOMMIT is pretty much completely useless on it’s own with the current set of opcodes?
  23. murchandamus commented at 4:08 pm on November 25, 2024: contributor
    I would like to see this proposal to get more review from other covenant researchers before it moves forward.
  24. in bip-PC.md:21 in a214597e9f outdated
    16+This BIP describes a new tapscript opcode `OP_PAIRCOMMIT` which
    17+provides limited vector commitment functionality in tapscript.
    18+
    19+When evaluated, the `OP_PAIRCOMMIT` instruction:
    20+* Pops the top two values off the stack,
    21+* takes the "PairCommit" tagged SHA256 hash of the stack elements,
    


    rot13maxi commented at 5:49 pm on November 25, 2024:
    consider linking to the section in bip340 about tagged hashes

    moonsettler commented at 11:04 pm on November 25, 2024:
    It is linked from Specification (line 53), not sure I would want to link from here.
  25. in bip-PC.md:29 in a214597e9f outdated
    24+## Motivation
    25+
    26+To do LN-Symmetry contracts that don't require the nodes to keep old states,
    27+we need to solve the data availability problem presented by unilateral closes.
    28+Channel peers must be able to reconstruct the script that spends an
    29+intermediate state.
    


    rot13maxi commented at 5:54 pm on November 25, 2024:
    what data needs to be available? how does PC solve that problem (does it stick the data in the witness and put a commitment somewhere covered by a signature? something else?)? Is this mechanism useful for things outside of LN-Symmetry?

    moonsettler commented at 6:04 pm on November 25, 2024:

    The data that needs to be available for state n is:

    0state-n-recovery-data { settlement-n-hash or state-n-balance }
    

    This is needed to reconstruct the whole script for the nth state address that the funds move to by the channel peer that only holds the latest state, so he can spend to the latest state.

    edit: Instead of an IF statement we could use different tap leaves (less optimal actually) and then merkle inclusion proof with sibling hashes would have to be known.


    moonsettler commented at 6:16 pm on November 25, 2024:

    Is this mechanism useful for things outside of LN-Symmetry?

    It was obviously our primary motivation, but I would not be surprised if other applications that use CSFS find a similar use for it.


    moonsettler commented at 6:20 pm on November 25, 2024:

    One way to think about the 3 opcodes (CSFS, IKEY, PC) is we decompose a CSFS variant that can use 1 byte pubkey (internal key) and can commit to a vector of stack elements as message. They thus become more generally useful, but to a limited degree without additional opcodes.

    Detailed introspection opcodes would also need vector commitments with CSFS, and as mentioned it would also be useful for CCV.


    moonsettler commented at 9:39 pm on November 27, 2024:
    Updated. I believe we can resolve these conversations? @rot13maxi @murchandamus
  26. moonsettler force-pushed on Nov 25, 2024
  27. moonsettler commented at 8:09 pm on November 26, 2024: contributor

    It looks like we gonna have to amend the PAIRCOMMIT BIP with some new use cases. Turns out within certain practical limitations any computational function can be proven out in the form of a merkle tree. The root hash of the merkle tree represents the function the leaves represent the inputs and output. Any 32 bit arithmetic function can certainly be proven out with this method. CAT itself with a limited set of inputs or limited input sizes can be proven out. At this point it’s an open question if this enables new behaviors not enabled by taproot MAST itself?

    Special thanks to: @JeremyRubin @Ademan @bigspider

    edit: Alternatively could consider imposing specific script limits that make PAIRCOMMIT explicitly less capable than MAST itself.

  28. moonsettler force-pushed on Nov 26, 2024
  29. moonsettler commented at 9:31 pm on November 26, 2024: contributor

    ACK on the current content.

    Might want to consider mentioning the deleted key function verification scheme we learned from @bigspider?

  30. moonsettler force-pushed on Nov 27, 2024
  31. Ademan commented at 5:40 am on November 27, 2024: none

    I think I’ve changed my mind a bit. We were talking about computing a merkle tree for f(u32,u32) as if it was trivial but after a quick experiment it seems like that would take hundreds of years to compute (am I being dumb here?) Instead, you can compute mul(u32,u32) -> u32 using 3 mul(u16,u16)s which is feasible to compute. The witness size is worse, ~32 * 32 * 3 = 3072 instead of 32 * 64 * 1 = 2048, but computing the tree for mul(u16,u16) is feasible using a naive algorithm on commodity hardware.

    The implication of this is that where a function can be decomposed into operations on smaller inputs, PAIRCOMMIT is massively more feasible to use than encoding things into a tap tree.

  32. bigspider commented at 9:39 am on November 27, 2024: contributor

    I think I’ve changed my mind a bit. We were talking about computing a merkle tree for f(u32,u32) as if it was trivial but after a quick experiment it seems like that would take hundreds of years to compute (am I being dumb here?) Instead, you can compute mul(u32,u32) -> u32 using 3 mul(u16,u16)s which is feasible to compute. The witness size is worse, ~32 * 32 * 3 = 3072 instead of 32 * 64 * 1 = 2048, but computing the tree for mul(u16,u16) is feasible using a naive algorithm on commodity hardware.

    Arithmetic and bitwise operations where inputs & outputs are small enough, can already be done in Script in cheaper ways. Merkle trees as lookup tables are only interesting for functions that are either extremely complex, or where preimages/images are larger than what Script can work with. Note that you can already do small indexed lookup tables more efficiently by just hard-coding them in Script (that is: push the table on the stack and use OP_PICK to read its entries), and these techniques are widely used (e.g. in BitVM).

    The implication of this is that where a function can be decomposed into operations on smaller inputs, PAIRCOMMIT is massively more feasible to use than encoding things into a tap tree.

    I think the only substantial difference is that in a Script where you need several lookups, you can do it with Merkle trees, while you can only do a single lookup with a precomputed taptree.

  33. moonsettler commented at 2:32 pm on November 27, 2024: contributor

    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.

    Is this correct? Any suggestions? @Ademan @bigspider

  34. moonsettler commented at 2:37 pm on November 27, 2024: contributor

    The implication of this is that where a function can be decomposed into operations on smaller inputs, PAIRCOMMIT is massively more feasible to use than encoding things into a tap tree.

    This is the main open question I believe. does it or does it not practically expand what we can already do? For example using PC to emulate smolCAT and using traditional methods with lookup tables could make 32 bit or even 64 bit arithmetics more feasible?

    edit: Within the 32 bit realm we can already use OP_ADD, I see little practical diff between <0x1234> <0x5678> CAT and <0x12340000> <0x5678> ADD. And it sounds like 64 bit smolCAT would be way too expensive to generate (and also to interact with trustlessly).

    (actually the above examples are wrong, because internally bitcoin script uses little endian, but should convey the point)

  35. Ademan commented at 3:07 pm on November 27, 2024: none

    Arithmetic and bitwise operations where inputs & outputs are small enough, can already be done in Script in cheaper ways. Merkle trees as lookup tables are only interesting for functions that are either extremely complex, or where preimages/images are larger than what Script can work with. Note that you can already do small indexed lookup tables more efficiently by just hard-coding them in Script (that is: push the table on the stack and use OP_PICK to read its entries), and these techniques are widely used (e.g. in BitVM).

    Even u16,u16 is quite a bit larger than I think is practical as a lookup table, but the efficiency for repeated operations is constant, obviously. The lookup table is less efficient for small numbers of operations (a u8,u8 table is 16k vs 1 u8,u8 proof is 0.4k) but the merkle tree loses quickly when those operations are repeated.

    The implication of this is that where a function can be decomposed into operations on smaller inputs, PAIRCOMMIT is massively more feasible to use than encoding things into a tap tree.

    I think the only substantial difference is that in a Script where you need several lookups, you can do it with Merkle trees, while you can only do a single lookup with a precomputed taptree.

    Right, and the key point is these merkle trees and lookup tables rapidly become infeasible to compute as the input size grows, so multiple smaller lookups is significantly more useful.

    EDIT: But your point is well taken that for smaller operations they can already be better accomplished by lookup tables.

  36. Ademan commented at 5:20 pm on November 27, 2024: none

    edit: Within the 32 bit realm we can already use OP_ADD, I see little practical diff between <0x1234> <0x5678> CAT and <0x12340000> <0x5678> ADD. And it sounds like 64 bit smolCAT would be way too expensive to generate (and also to interact with trustlessly).

    (actually the above examples are wrong, because internally bitcoin script uses little endian, but should convey the point)

    Yeah for arbitrary 8 byte strings smolCAT seems infeasible to compute the table or merkle tree for. After a bit of conversation on IRC it could probably be feasible for arbitrary f(b[4],b[4]) -> b[8] with a custom ASIC¹ or maybe a cluster of FPGAs in a span of ~a few years but that would not be very useful for the average person.

    Bit shifts over 32 bit integers seems pretty feasible though, that’s f(u32,u6)->u32 (maybe save some space by special casing shift = 0). it seems like my incredibly naive, unoptimized, single-core experiment could calculate that merkle tree in ~96 hours. Of course the proof is ~1.2k and users would likely need multiple, but the lookup table for that wouldn’t fit in a block anyway so maybe something new is possible?

    You can also separate positive and negative shifts, and maybe break it down into multiple rounds of shifts 1-3 or something (or 1k for a proof for a constant shift)

    [1]: afaik existing ASICs operate on block headers so couldn’t help

  37. Add: PAIRCOMMIT 4838e65175
  38. moonsettler force-pushed on Nov 27, 2024
  39. Update links 7da94c04d0
  40. Add: Use with future updates; expand Rationale 0d4df2d2e5
  41. moonsettler commented at 9:42 pm on November 27, 2024: contributor

    I think this BIP is already way more verbose than it was supposed to be.

    It would be useful if we could reference it by a number. Can we get a BIP number assigned? Not asking for a merge yet.

  42. Fix: popstack(stack) -> stack.pop_back()
    popstack() has a redundant check @Psifour
    f38e9a08c9
  43. Fix: bip-0347 link 66c3376062
  44. moonsettler requested review from murchandamus on Dec 4, 2024
  45. moonsettler commented at 3:37 pm on December 5, 2024: contributor

    Should we add this table to this BIP? And it’s not just vBytes but also the number of sigops to consider, which is a cost all nodes on the p2p network have to bear.

    edit: I think it looks like this:

    Method ChannelS UpdateSc UpdateWi 1-Update 2-Update
    APO-annex 2.25 vB 28.25 vB 25 vB 305 vB 461.5 vB
    APO-return 2.25 vB 28.25 vB 16.5 vB 338.5 vB 528.5 vB
    CTV+CSFS+IKEY 2.75 vB 12.25 vB 24.5 vB 331 vB 513 vB
    CTV+CSFS 11 vB 20.5 vB 24.5 vB 347.5 vB 537.75 vB
    LNhance 3 vB 12.5 vB 32.75 vB 297.75 vB 446.25 vB
    CTV+CSFS+VAULT 18.75 vB 30 vB 35 vB 333.75 vB 502.25 vB
    rekey 7.25 vB 16.75 vB 73.75 vB 347.25 vB 541 vB
    Method ForceC Update Settle OP_RETURN
    APO-annex 1 SigOp 1 SigOp 1 SigOp
    APO-return 1 SigOp 1 SigOp 1 SigOp X
    CTV+CSFS+IKEY 1 SigOp 1 SigOp CTV X
    CTV+CSFS 1 SigOp 1 SigOp CTV X
    LNhance 1 SigOp 1 SigOp CTV
    CTV+CSFS+VAULT 2* SigOp 2* SigOp CTV
    rekey 3 SigOp 3 SigOp CTV

    * VAULT is not exactly a SigOp, but close enough. Has a budget cost of 1.2 SigOps.

  46. Add: Cost comparison 018d28c967
  47. JeremyRubin commented at 4:06 am on December 6, 2024: contributor
    tbh i have no idea how to read that table, so might be good to have clearer labeling somehow / break down where the accounting came from?
  48. moonsettler commented at 9:37 am on December 6, 2024: contributor
  49. murchandamus commented at 7:08 pm on December 6, 2024: contributor

    It would be useful if we could reference it by a number. Can we get a BIP number assigned? Not asking for a merge yet.

    Looking at the Motivation section, it seems to me that the main application for this proposal would be a construction that depends on three other undeployed proposals some of which are themselves draft stage or pre-draft. This proposal feels a bit hypothetical at this point. I’ll get back to you next week.

  50. moonsettler commented at 7:23 pm on December 6, 2024: contributor

    This proposal feels a bit hypothetical at this point.

    While PAIRCOMMIT would only be truly useful with certain other future upgrades, it is proposed to activate in a bundle with said updates. We are in the process of trying to reach consensus on said package.

    It’s unlikely I would withdraw OP_PAIRCOMMIT, unless OP_CAT got activated first.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-06 22:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me