Recapping the relationship between CTV and ANYPREVOUT::
It is known that there is a significant amount of overlap in the applications that are enabled by the CTV and ANYPREVOUT proposals despite the fact that their primary applications (congestion control for CTV and eltoo lightning channels for ANYPREVOUT) are quite distinct.
In particular, ANYPREVOUT can enable most of the applications of CTV, albeit with a higher cost. The primary functionality of CTV is to allow a scriptPubKey to make a commitment to its spending transaction's hash with the input's TXID excluded from the hash. This exclusion is necessary because the scriptPubKey is hashed into the input's TXID, and including the TXID would cause a cycle of hash commitments, which is impossible to construct. On the other hand, ANYPREVOUT defines a signature hash mode that similarly excludes the inputs TXID for its purpose of rebindable signatures.
This means that ANYPREVOUT can mimic most of the properties of CTV by committing both a public key along with an ANYPREVOUT signature inside scriptPubKey. In fact, the only reason Bitcoin doesn't have covenants today is due to this cycle between scriptPubKeys and the TXIDs that occur in all the sighash modes.
The major differences between simulating CTV via ANYPREVOUT and the actual CTV proposal is: (1) The cost of simulating CTV. With CTV the spending transaction is committed using a hash of 32 bytes, while simulating it with ANYPREVOUT requires 64 bytes for a signature, and 32 bytes for some public key, plus a few more bytes for various flags. Some of that cost could be reduced by using the inner public key (1 byte representation) and, if we had CAT, maybe by assembling the signature from reusable pieces (i.e. setting the nonce of the commited signature equal to the public key).
The other major difference is: (2) CTV's transaction hash covers values such as the number of inputs in the transaction and their sequence numbers, which ANYPREVOUT does not cover. CTV's hash contains enough information so that when combined with the missing TXIDs, you can compute the TXID of the spending transaction. In particular if the number of inputs is committed to being 1, once the scriptpubkey's transaction id is known and committed to the blockchain, the TXID of its spending transaction is deducible. And if that transaction has outputs that have CTV commitments in them, you can deduce their spending TXIDs in turn. While this is a pretty neat feature, something that ANYPREVOUT cannot mimic, the main application for it is listed as using congestion control to fund lightning channels, fixing their TXIDs in advance of them being placed on chain. However, if ANYPREVOUT were used to mimic CTV, then likely it would be eltoo channels that would be funded, and it isn't necessary to know the TXIDs of eltoo channels in advance in order to use them.
An Alternative Proposal::
Given the overlap in functionality between CTV and ANYPREVOUT, I think it makes sense to decompose their operations into their constituent pieces and reassemble their behaviour programmatically. To this end, I'd like to instead propose OP_TXHASH and OP_CHECKSIGFROMSTACKVERIFY.
OP_TXHASH would pop a txhash flag from the stack and compute a (tagged) txhash in accordance with that flag, and push the resulting hash onto the stack.
OP_CHECKSIGFROMSTACKVERIFY would pop a pubkey, message, and signature from the stack and fail if the signature does not verify on that message.
CTV and TXHASH have roughly equivalent functionality. 'CTV DROP' can be simulated by '<ctv_style_flag> TXHASH EQUALVERIFY'. The reverse is also true where '<ctv_style_flag> TXHASH' can be simulated by CTV by '<ctv-result-from-witness-stack> CTV', however, as you can see, simulating TXHASH from CTV is much more expensive than the other way around, because the resulting 32-byte hash result must be included as part of the witness stack.
'<anyprevout-pubkey> CHECKSIGVERIFY can be simulated by '<apo_style_flag> TXHASH <pubkey> CHECKSIGFROMSTACKVERIFY'. Here we see the advantage of pushing the hash value onto the stack. APO can be simulated without needing to include a copy of the resulting txhash inside the witness data.
In addition to the CTV and ANYPREVOUT applications, with CHECKSIGFROMSTACKVERIFY we can verify signatures on arbitrary messages signed by oracles for oracle applications. This is where we see the benefit of decomposing operations into primitive pieces. By giving users the ability to program their own use cases from components, we get more applications out of fewer op codes!
Caveats::
First, I acknowledge that replicating the behaviour of CTV and ANYPREVOUT does cost a few more bytes than using the custom purpose built proposals themselves. That is the price to be paid when we choose the ability to program solutions from pieces. But we get to reap the advantages of being able to build more applications from these pieces.
Unlike CTV, TXHASH is not NOP-compatable and can only be implemented within tapscript. In particular, bare CTV isn't possible with this proposal. However, this proposal doesn't preclude the possibility of having CTV added to legacy script in while having TXHASH added to tapscript.
For similar reasons, TXHASH is not amenable to extending the set of txflags at a later date. In theory, one could have TXHASH abort-with-success when encountering an unknown set of flags. However, this would make analyzing tapscript much more difficult. Tapscripts would then be able to abort with success or failure depending on the order script fragments are assembled and executed, and getting the order incorrect would be catastrophic. This behavior is manifestly different from the current batch of OP_SUCCESS opcodes that abort-with-success just by their mere presence, whether they would be executed or not.
I believe the difficulties with upgrading TXHASH can be mitigated by designing a robust set of TXHASH flags from the start. For example having bits to control whether (1) the version is covered; (2) the locktime is covered; (3) txids are covered; (4) sequence numbers are covered; (5) input amounts are covered; (6) input scriptpubkeys are covered; (7) number of inputs is covered; (8) output amounts are covered; (9) output scriptpubkeys are covered; (10) number of outputs is covered; (11) the tapbranch is covered; (12) the tapleaf is covered; (13) the opseparator value is covered; (14) whether all, one, or no inputs are covered; (15) whether all, one or no outputs are covered; (16) whether the one input position is covered; (17) whether the one output position is covered; (18) whether the sighash flags are covered or not (note: whether or not the sighash flags are or are not covered must itself be covered). Possibly specifying which input or output position is covered in the single case and whether the position is relative to the input's position or is an absolute position.
That all said, even if other txhash flag modes are needed in the future, adding TXHASH2 always remains an option.
Interactions with potential future opcodes::
We should give some consideration on how these opcodes may interact with future opcodes such as CAT, rolling SHA256 opcodes, or how it might interface with other covenant opcodes that may do things like, directly push input or output amounts onto the stack for computation purposes, opcodes which have been added to the Elements project.
With CAT and/or rolling SHA256 opcodes and/or existing SHA256 opcodes, the CHECKSIGFROMSTACKVERIFY could verify signatures on programmatically assembled messages. Also, in combination with multiple calls to TXHASH, could be used to create signatures that commit to complex subsets of transaction data.
If new opcodes are added to push parts of the transaction data direction onto the stack, e.g. OP_INSPECTOUTPUTVALUE, there is perhaps concern that they would obsolete TXHASH, since, in the presence of rolling SHA256 opcodes, TXHASH could be simulated. However, given that TXHASH can compactly create a hash of large portions of transaction data, it seems unlikely that TXHASH would fall into disuse. Also, a combination of TXHASH and transaction introspection opcodes can be used to build "subtractive covenants".
The usual way of building a covenant, which we will call "additive covenants", is to push all the parts of the transaction data you would like to fix onto the stack, hash it all together, and verify the resulting hash matches a fixed value. Another way of building covenants, which we will call "subtractive covenants", is to push all the parts of the transaction data you would like to remain free onto the stack. Then use rolling SHA256 opcodes starting from a fixed midstate that commits to a prefix of the transaction hash data. The free parts are hashed into that midstate. Finally, the resulting hash value is verified to match a value returned by TXHASH. The ability to nicely build subtractive covenants depends on the details of how the TXHASH hash value is constructed, something that I'm told CTV has given consideration to.
_______________________________________________