# CTV+CSFS: Can we reach consensus on a first step towards covenants?

**URL:** <https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509>\
**Category:** Protocol Design\
**Tags:** softfork, covenants, introspection\
**Created:** [March 10, 2025, 10:35pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509 "2025-03-10T22:35:25Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![securitybrahh](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/securitybrahh/32/2015_2.png) [@securitybrahh](https://delvingbitcoin.org/u/securitybrahh)\
**Post date:** [May 8, 2025, 7:23am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/64 "2025-05-08T07:23:41Z")

</div>

Also the core-devs has put a “regtest” label on the PR, can I see thr opcodes running on something like mempool.space?

---

<div class="post-metadata">

**Author:** ![moonsettler](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/moonsettler/32/38_2.png) [@moonsettler](https://delvingbitcoin.org/u/moonsettler)\
**Post date:** [May 27, 2025, 2:44pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/65 "2025-05-27T14:44:18Z")

</div>

regtest means you can only use it on your own computer on a private blockchain.

---

<div class="post-metadata">

**Author:** ![securitybrahh](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/securitybrahh/32/2015_2.png) [@securitybrahh](https://delvingbitcoin.org/u/securitybrahh)\
**Post date:** [May 28, 2025, 10:08am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/66 "2025-05-28T10:08:00Z")

</div>

lol, atleast let me run on some test net that we all can view through mempool space UI.

---

<div class="post-metadata">

**Author:** ![Chris\_Stewart\_5](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/chris_stewart_5/32/296_2.png) [@Chris\_Stewart\_5](https://delvingbitcoin.org/u/Chris_Stewart_5)\
**Post date:** [June 5, 2025, 12:04am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/67 "2025-06-05T00:04:14Z")

</div>

Has anyone actually published a branch that has both CTV+CSFS? From skimming through this topic I don’t see one. It would be nice to have one on top of the major latest release of bitcoin core for integration testing the 2 opcodes together.

---

<div class="post-metadata">

**Author:** ![AntoineP](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/antoinep/32/483_2.png) [@AntoineP](https://delvingbitcoin.org/u/AntoineP)\
**Post date:** [June 5, 2025, 1:29pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/68 "2025-06-05T13:29:31Z")

</div>

Good point. Greg [has a PR](https://github.com/bitcoin-inquisition/bitcoin/pull/72) to introduce CSFS to inquisition. This is in effect a branch with both CTV+CSFS. It’s worth noting nobody bothered reviewing it in the past 3 months.

---

<div class="post-metadata">

**Author:** ![Chris\_Stewart\_5](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/chris_stewart_5/32/296_2.png) [@Chris\_Stewart\_5](https://delvingbitcoin.org/u/Chris_Stewart_5)\
**Post date:** [June 5, 2025, 9:47pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/69 "2025-06-05T21:47:46Z")

</div>

I think the @RobinLinus and @ajtowns interactions on the BitVM & CTV+CSFS thread illustrates the subtle foot guns that come with OP\_CTV as an OP\_NOP and OP\_SUCCESS. I don’t think I would have caught this subtle vulnerability that comes with supporting legacy Script.

This interaction occurred after the posts on this thread arguing about OP\_NOP support, so I feel like its worthwhile to highlight it here.

> [@How CTV+CSFS improves BitVM bridges](https://delvingbitcoin.org/t/how-ctv-csfs-improves-bitvm-bridges/1591/8):
>
> where `<H>` locks in where the output goes to, and input 2’s scriptSig. But because H is only committing to the second input’s scriptSig, then it’s easy to construct another utxo that can be used instead, eg one with the (non-standard) scriptPubKey `OP_2DROP OP_TRUE`:
> 
> ```auto
> utxo C: 500 sats, scriptPubKey: OP_2DROP OP_TRUE
> 
> input 1: utxo A, no witness/scriptSig
> input 2: utxo C, scriptSig = "<S;NONE|ANYONECANPAY>" "<P> CHECKSIG"
> output: whatever
> 
> ```
> 
> That allows utxo A to be spent via the CTV path independently of whether utxo B has already been spent/burnt, which, as far as I can see, breaks the protocol you’re trying to enforce.
> 
> (I’m assuming in a real example utxo B’s spend condition is more complicated than `<P> CHECKSIG`, as otherwise the availability of a NONE|ANYONECANPAY signature means it can be spent immediately, so a griefer could fairly easily prevent the happy path from ever being taken)

It seems like this could be worked around since OP\_CTV does commit to the scriptSig according to instagibbs

> [@How CTV+CSFS improves BitVM bridges](https://delvingbitcoin.org/t/how-ctv-csfs-improves-bitvm-bridges/1591/9):
>
> The scriptSig could include the `CHECKSIG` opcode directly, contra standardness rules. 😬
> 
> In the original idea, a p2sh redeemscript is just pushes, so the spk could just be blank and it would pass, since cleanstack isn’t consensus anyways.

However this seems rather unpleasant.

I think Jeremy Rubin is conceding the point that at least for p2sh OP\_CTV is broken?

> [@How CTV+CSFS improves BitVM bridges](https://delvingbitcoin.org/t/how-ctv-csfs-improves-bitvm-bridges/1591/11):
>
> This is an interesting point; without some sort of “stack sentinel” that guarantees a specific script type, using CTV as a gadget for any P2SH type seems broken, as you can replace it with a legacy script that does something else. This is “confusing” because you cannot replace it with a p2sh script that does something else. I can make an effort to better document this issue…

Which leaves us with only spending “raw”/“bare” outputs to be able to commit to meaningful data in the scriptSig with CTV.

Is the juice really worth the squeeze for committing to scriptSig data?

---

<div class="post-metadata">

**Author:** ![instagibbs](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/instagibbs/32/28_2.png) [@instagibbs](https://delvingbitcoin.org/u/instagibbs)\
**Post date:** [June 6, 2025, 11:47am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/70 "2025-06-06T11:47:13Z")

</div>

I’ve come to see this capability of CTV (committing to other prevouts in very round-about way) as an anti-feature, an unexpected capability that is so sharp-edged that if it’s something we want we should explicitly design for it instead to discourage such bizarre usage.

Alternatively we could remove the capability by making non-empty scriptSigs fail the script execution. This of course only makes sense in a post-segwit world only which I’ve already advocated above as a taproot-only push opcode.

---

<div class="post-metadata">

**Author:** ![josh](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/josh/32/95_2.png) [@josh](https://delvingbitcoin.org/u/josh)\
**Post date:** [June 6, 2025, 5:37pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/71 "2025-06-06T17:37:06Z")

</div>

> This of course only makes sense in a post-segwit world only which I’ve already advocated above as a taproot-only push opcode.

@instagibbs If a taproot-only push opcode is the way to go, would it make sense to introduce a new witness version for bare tapscript?

That way, you can still make bare CTV commitments (leaving other types of bare scripts non-standard).

---

<div class="post-metadata">

**Author:** ![instagibbs](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/instagibbs/32/28_2.png) [@instagibbs](https://delvingbitcoin.org/u/instagibbs)\
**Post date:** [June 6, 2025, 8:41pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/72 "2025-06-06T20:41:26Z")

</div>

> [@josh](#):
>
> If a taproot-only push opcode is the way to go, would it make sense to introduce a new witness version for bare tapscript?

I did here [CTV+CSFS: Can we reach consensus on a first step towards covenants? - #58 by instagibbs](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/58)

I find it nice to consider both separately, even if they both end up being adopted.

---

<div class="post-metadata">

**Author:** ![jamesob](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/jamesob/32/271_2.png) [@jamesob](https://delvingbitcoin.org/u/jamesob)\
**Post date:** [June 7, 2025, 2:06pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/73 "2025-06-07T14:06:24Z")

</div>

> [@instagibbs](#):
>
> FYI: after discussion a while back, I hacked together very small loc changes that:
> 
> 1. Makes bare CTV a first class citizen
> 2. Converts CTV into a push-onto-stack taproot-only opcode

This is a cool patch, thanks for doing it.

I still prefer the existing CTV impl. for a few reasons:

1. Bare legacy CTV is upgradeable (i.e. \>32byte CTV hashes). Though you could make your patch upgradeable by returning true for any witV2 with a program size of over 32 bytes.
2. In wit v0 CTV, you can have scripts that are more complicated than just a single CTV invocation, but avoid the Taproot control block overhead of 33vB (e.g. in [simple-ctv-vault](https://github.com/jamesob/simple-ctv-vault/blob/7dd6c4ca25debb2140cdefb79b302c65d1b24937/main.py#L303-L316)). 33vB may well be worth fretting over in the future.
3. This is probably fringe, but one “nice” thing about bare CTV legacy scripts is that because they don’t have an associated address, accidental address reuse by a human is impossible (i.e. erroneous send to an already-setup vault). ~~Of course your witV2 scheme doesn’t define an address format, but it would be easy to.~~ Edit: witV2 by default [uses bech32m addresses](https://github.com/bitcoin/bitcoin/blob/e2174378aa8a339c7be8b4e91311513ed520a16d/src/key_io.cpp#L68-L78).

---

<div class="post-metadata">

**Author:** ![jamesob](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/jamesob/32/271_2.png) [@jamesob](https://delvingbitcoin.org/u/jamesob)\
**Post date:** [June 8, 2025, 4:24pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/74 "2025-06-08T16:24:54Z")

</div>

@instagibbs Maybe it goes without saying, but I think it’d be totally reasonable to layer on a tapscript-only `OP_CHECKTEMPLATE` to the existing proposal. If it saves ~~32 vbytes~~ 8WU for the Lightning case and likely others, I think that’s great.

---

<div class="post-metadata">

**Author:** ![instagibbs](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/instagibbs/32/28_2.png) [@instagibbs](https://delvingbitcoin.org/u/instagibbs)\
**Post date:** [June 9, 2025, 3:39pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/75 "2025-06-09T15:39:25Z")

</div>

> [@jamesob](#):
>
> Bare legacy CTV is upgradeable

No other output lengths would be defined for the “P2CTV” case, there’s no difference in this respect.

> [@jamesob](#):
>
> 33vB may well be worth fretting over in the future.

33WU, or \<9vB. I don’t find byte pinching over hypotheticals very persuasive but other’s mileage may vary.

> [@jamesob](#):
>
> This is probably fringe, but one “nice” thing about bare CTV legacy scripts is that because they don’t have an associated address

I know we differ on this but I expect very little bare CTV usage vs some form of script. We can’t protect people in script hash land; I think that ship sailed a long time ago.

* * *

The proposal is materially different than before with CSFS added. Let’s avoid sunk cost thinking.

---

<div class="post-metadata">

**Author:** ![jamesob](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/jamesob/32/271_2.png) [@jamesob](https://delvingbitcoin.org/u/jamesob)\
**Post date:** [June 10, 2025, 1:10am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/76 "2025-06-10T01:10:30Z")

</div>

Another more practical point in favor of making CTV available in witness v0 is that many (or most?) HSMs do not yet natively support Schnorr signatures - and for existing installations, may never. There is likely overlap between companies who currently use such HSMs (making witness v0 the default) and companies who would like to make use of CTV vaults.

---

<div class="post-metadata">

**Author:** ![instagibbs](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/instagibbs/32/28_2.png) [@instagibbs](https://delvingbitcoin.org/u/instagibbs)\
**Post date:** [June 10, 2025, 3:38pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/77 "2025-06-10T15:38:09Z")

</div>

That’s a reasonable point, under the restricted set of functionality that encompasses a hash-assertion and a disjoint signature over the transaction itself.

So you could have a “next tx” transition or override with some (non-aggregated) key or require both.

---

<div class="post-metadata">

**Author:** ![jamesob](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/jamesob/32/271_2.png) [@jamesob](https://delvingbitcoin.org/u/jamesob)\
**Post date:** [June 18, 2025, 2:43am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/78 "2025-06-18T02:43:00Z")

</div>

Brief overview of my current thoughts, for whatever they’re worth:

I’d be happy to modify BIP-119 to omit legacy script support for CTV if there’s a 34-byte “witness v2” along the lines of what @instagibbs sketched out.

My hold out here had been that I thought the BitVM “sibling input requirement” trick relies upon legacy use, but it does not. Note that I still think CTV availability in witness v0 is worth preserving for reasons mentioned above.

If there’s demand to introduce a push-style `OP_TEMPLATEHASH` that puts the CTV digest on the stack, that sounds like a totally reasonable and low-effort/risk enhancement to me.

* * *

Do the stakeholders opining here think there could be consensus around this? Namely:

- BIP-119 modified to remove legacy script support (but retaining wit v0 support),
- definition of a witness v2 per [instagibb’s patch](https://github.com/instagibbs/bitcoin/commit/9b5ae77d97222efc2328c1916f790c7f67cf10b3), and
- inclusion of a tapscript-only `OP_TEMPLATEHASH`?

---

<div class="post-metadata">

**Author:** ![sjors](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/sjors/32/59_2.png) [@sjors](https://delvingbitcoin.org/u/sjors)\
**Post date:** [June 23, 2025, 3:22pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/80 "2025-06-23T15:22:42Z")

</div>

> [@instagibbs](#):
>
> I do think it would accelerate updating to PTLCs, f.e., even if symmetry per-se is never adopted. Re-bindable signatures just makes life so much less of a headache when stacking protocols…

Can you clarify the situation with regards to PTLC (without LN Symmetry)? My understanding is that PTLC is an enormous privacy upgrade, since it removes the trail of identical hash pre-images along a (split) route. (especially in a scenario where an adversary is gradually collecting log files through nefarious means)

I guess I’m stuck in 2021 when we thought that just Taproot would do the trick.

Is it merely easier if we add CSFS (plus CTV)? Or is it nearly impossible without that?

Since it tends to take a few years for a soft fork to activate and for a protocol like Lightning to take advantage of it, by that time, could we be in situation where already achieved PTLC the hard way? It would still be a welcome simplification, but not introducing something new. Or do you reckon we’ll have PTLC sooner despite the extra step of activating a soft fork?

---

<div class="post-metadata">

**Author:** ![instagibbs](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/instagibbs/32/28_2.png) [@instagibbs](https://delvingbitcoin.org/u/instagibbs)\
**Post date:** [June 23, 2025, 3:37pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/81 "2025-06-23T15:37:14Z")

</div>

> [@sjors](#):
>
> Is it merely easier if we add CSFS (plus CTV)? Or is it nearly impossible without that?

Take a look [here](https://gist.github.com/instagibbs/1d02d0251640c250ceea1c66665ec163) to see what complications arise from PTLCs on today’s protocols. It’s by no means impossible, but with rebindable signatures it just gets significantly simpler.

I will not try to predict uptake on established protocols however. There’s a long list of improvements that users actually care about, and PTLCs isn’t one of them generally.

---

<div class="post-metadata">

**Author:** ![ajtowns](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/ajtowns/32/417_2.png) [@ajtowns](https://delvingbitcoin.org/u/ajtowns)\
**Post date:** [July 2, 2025, 5:01am UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/82 "2025-07-02T05:01:19Z")

</div>

> [@sjors](#):
>
> I guess I’m stuck in 2021 when we thought that just Taproot would do the trick.

I think there’s also a lack of tooling/standardisation for doing a PTLC reveal in combination with a musig 2-of-2 (which would be efficient on-chain), or even general tx signatures (ie `x CHECKSIGVERIFY y CHECKSIG`).

The efficient way of doing PTLCs would be to have a partially-presigned musig2 signature for the redeem tx, where completing the signature reveals the PTLC secret to the other party. But this would require adaptor signature support for musig2, and that’s not part of the spec and was removed from the secp256k1 implementation see [pr#1479](https://github.com/bitcoin-core/secp256k1/pull/1479). Doing it less efficiently as a separate adaptor signature would work too, but even plain adaptor signatures for schnorr sigs also isn’t available in secp256k1.

These also aren’t included even in the more experimental secp256k1-zkp project, see [pr#299](https://github.com/BlockstreamResearch/secp256k1-zkp/pull/299), though secp256k1-zkp does have support for ECDSA-based adaptor signatures ([pr#117](https://github.com/BlockstreamResearch/secp256k1-zkp/pull/117)) and adaptor signatures in the old musig scheme that predates musig2 and [BIP-327](https://github.com/bitcoin/bips/blob/36618d1c3c6b1559d0ce69fd958191b8789f350a/bip-0327.mediawiki) (see [musig.md](https://github.com/BlockstreamResearch/secp256k1-zkp/blob/6152622613fdf1c5af6f31f74c427c4e9ee120ce/src/modules/musig/musig.md)).

If the tooling were ready, I could see PTLC support being added as a “let’s get it in early so it’s already widely supported when we actually want to enable it”, but I don’t think anyone considers it a high enough priority to put in the work to get the crypto stuff standardised and polished. Making the unhappy path more efficient is something that could be done later on a per-peer basis without too much hassle.

Having CAT+CSFS available would avoid the tooling issue, at a cost in on-chain efficiency (though only in the unhappy path, of course), using 102 witness bytes for a PTLC reveal versus 56/67 witness bytes for a HTLC reveal. In particular, the script `<R> CAT <G> DUP CSFS` can be satisfied by having `<s>` on the stack where `s*G = R + H(R,G,G)*G`, so the preimage of `R` can be calculated as `r = s - H(R,G,G)`, with straightforward ECC maths, and no need for secret keys. I think with only CSFS available you continue having similar tooling problems, because you need to use adaptor signatures to prevent your counterparty from choosing a different R value for the signature.

EDIT: `<R> TUCK SWAP CAT SWAP DUP CSFS`, which uses R for the pubkey and message as well as the nonce, probably works better – 73 witness bytes for the reveal is pretty close to the HTLC version, and the calculation is just `r = s/(1 + H(R,R,R))` which is only slightly more annoying, in that it requires a modular division. (Maybe `OP_0` would be a better “message” in this case)

(These issues are independent of the update complexity and peer protocol updates @instagibbs describes above)

---

<div class="post-metadata">

**Author:** ![instagibbs](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/instagibbs/32/28_2.png) [@instagibbs](https://delvingbitcoin.org/u/instagibbs)\
**Post date:** [July 2, 2025, 1:37pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/83 "2025-07-02T13:37:58Z")

</div>

> [@ajtowns](#):
>
> In particular, the script `<R> CAT <G> DUP CSFS` can be satisfied by having `<s>` on the stack where `s*G = R + H(R,G,G)*G`, so the preimage of `R` can be calculated as `r = s - H(R,G,G)`, with straightforward ECC maths, and no need for secret keys

To be clear, does this include per-hop blinding? My PTLC context has completely paged out of memory.

---

<div class="post-metadata">

**Author:** ![ajtowns](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/ajtowns/32/417_2.png) [@ajtowns](https://delvingbitcoin.org/u/ajtowns)\
**Post date:** [July 2, 2025, 4:21pm UTC](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509/84 "2025-07-02T16:21:12Z")

</div>

Per-hop blinding just means that you have inbound value `R1` and outbound value `R2=R1+kG`, where `k` is a per-hop constant known only to you and the person initiating the payment, so when you receive/calculate `r2` on your outbound link, you can calculate `r1=r2-k` to claim the inbound funds. You just need to relate r1/R1 (and r2/R2) on-chain, you don’t need to relate r1/r2 or R1/R2 on-chain (which would remove the privacy benefit anyway).

[Previous page](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509.md?page=3)

[Next page](https://delvingbitcoin.org/t/ctv-csfs-can-we-reach-consensus-on-a-first-step-towards-covenants/1509.md?page=5)
