What on earth is CatVM?
Taproot Wizards released a comic called CatVM yesterday. I wouldn’t call it a white paper, it’s a real academic document for adults. Scattered amongst the outrageous childish stories were some valuable technical insights into the cartoons regarding various proposed expansions of the Bitcoin ecosystem. Of course, in true comics fashion, it’s buried between wild exaggeration and embellishment.
The ultimate goal of the cartoon was to propose a new mechanism for moving in and out of the scaling layer built on top of Bitcoin. To separate the actual proposal from the cartoon, we need to break down the two parts involved.
building blocks
Rijndael’s first OP_CAT experiment was to build a vault, a scheme that allows users to withdraw funds from a vault by creating intermediate “staging” transactions. This will initiate a timelock, during which the funds can be sent back to the vault or secure cold storage wallet at any time, after the timelock ends the user is free to withdraw the funds to the destination selected when initiating the withdrawal process. These are Only There are two ways you can spend Bitcoin sent to your vault script:
Describing the full mechanics of how this is done is essentially an article in itself, so I’ll do something I don’t normally do and give this up as “magic.” (Explained here by Andrew Poelstra) What this “magic” allows you to do by creating a non-standard Schnorr signature and with the help of OP_CAT is to build a transaction whose signature verification is opposed to the script stack. This allows you to force certain parts of the transaction to match exactly what is predefined. It also allows you to push the output of a previous transaction onto the stack as part of building a transaction that uses that output. This means that you can compare the output of a spending transaction with the output of a previous transaction. This allows us to compare and ensure that certain parts of the old transaction output match certain parts of the new output. That is, the script or amount. This allows you to “carry over” some of the old output to the new output and enforce it.
Another thing you can do with OP_CAT without having to modify and experiment with Rijndael yourself is to check the branches of the Merkle tree. Since you can CAT stack items together and Bitcoin already supports hashing of data on the stack, you can slowly build a Merkle tree root from leaf nodes with internal nodes. Hash the two pieces together to get one hash, which you then hash as a pair hash, and so on. Eventually we get the root hash from the stack. You can then compare OP_EQUAL against the root hash predefined in your locking script.
unilateral withdrawal
These two components are sufficient to facilitate a unilateral withdrawal mechanism from group-shared UTXOs. Merkle roots can be included in transactions using OP_RETURN or another mechanism that commits to each user’s leaf nodes. The UTXO script can be configured to allow any user with a balance to attempt a withdrawal. To do so, they construct a transaction on the stack, providing proof of approval such as a Merkle branch pledging the amount they are entitled to, a public key to verify the signature, and verifying that the appropriate conditions are met.
Similar to Rijndael’s OP_CAT vault, this withdrawal transaction functions as a staging point. User funds are limited by a time lock and withdrawals cannot be completed until expiration. At any time before the time lock expires, another user can generate a fraud proof to stop the withdrawal and put the funds back into the group UTXO script. This is possible thanks to OP_CAT’s Merkle tree verification capabilities. If someone has previously withdrawn funds from a UTXO using a specific Merkle branch, that will be included somewhere in the block. They can be proven by constructing a transaction that includes the SPV proof of that transaction within a real block, which can be verified using OP_LESSTHANOREQUAL to ensure that the block header meets the minimum difficulty level. on the stack Merkle branch is what was used earlier. This helps prevent duplicate withdrawals.
In addition to this, we can use the “CAT on the stack” trick to ensure that certain parts of the previous transaction are included in the next transaction, thus ensuring that the current Merkle root is passed on to the next transaction after a successful one. withdrawal. You can also ensure that any changes resulting from leaving revert back to the group shared script. This is a script that allows one user to withdraw funds and then allow the remaining users to do so, ensuring UTXO changes are locked, etc. Any user can unilaterally withdraw funds at any time, in any order, with the guarantee that the remaining funds will remain accessible to the remaining users.
VM part
The reader should be familiar with the basic ideas of BitVM. You can perform arbitrary calculations, break them down into their components, and insert them into a large taproot tree, turning those calculations into a back-and-forth challenge/response game. This allows you to lock your bitcoins with more complex conditions than those directly supported by Bitcoin Script itself. The only downside is that you need to create a large number of pre-signed transactions to facilitate this.
A requirement for using pre-signed transactions is that the coins can be guaranteed to be spent again with a large taproot tree encoding them unless an exit condition is reached in the challenge/response dynamic. OP_CAT and the ability to “carry over” data from previous transactions can be used to ensure this without the need for pre-signed transactions.
So not only does this approach allow any user to unilaterally terminate it on their own, but it also allows locking conditions supported by the second layer that are not supported by Bitcoin Script to actually be enforced in the withdrawal process. This means that if some coins are encumbered by a smart contract that the base layer does not understand and are withdrawn at the second layer, these more complex conditions can still be correctly resolved by the base layer when the coins are withdrawn.
missing piece
One thing OP_CAT does not enable is updating the Merkle tree root, which verifiably represents a user’s off-chain balance. Already committed state can be enabled to facilitate unilateral withdrawals, but this is because entire sections of the tree are actually placed on the chain and verified. By definition, updating that root off-chain means not leaving the data on-chain. This indicates a problem. CAT alone has no way to efficiently ensure that all changes to the Merkle tree have been properly approved by the relevant users.
Someone needs to be trustworthy and, given the nature of things, be able to use UTXOs wherever they want, and efficiently replace existing state roots with new ones to represent any off-chain balance changes. To do this in a trustless way, you need a new opcode in addition to OP_CAT: OP_ZKVERIFY.
But without OP_ZKVERIFY this wouldn’t be the end of the world. The entity updating the Merkle root for off-chain transfers can be n-of-n multi-signature, and all root changes must be approved by 100% of the participants. This results in the same trust model as the BitVM-based peg, where as long as there is only one honest participant, no one can have their funds stolen. However, with regard to the withdrawal process, there are significant improvements over existing BitVM designs.
In BitVM peg, there is no unilateral withdrawal mechanism for users. Peg operators must be trusted to perform user withdrawals in the knowledge that they can recover funds spent on the BitVM peg in a relatively untrustworthy manner. The incentives for this are very solid, but if a user wants to exit the system, they essentially need permission from someone else, but they can’t do so themselves. CatVM allows users to withdraw funds unilaterally and operators do not have to advance their own liquidity to process withdrawals.
finish
Overall, the design is imperfect in terms of construction. This is not what we call layer 2 per se. This is the core of the process – the mechanism and structure of how funds are locked at Layer 2, and how users can withdraw their funds. It certainly offers great flexibility and usability.
In the worst-case scenario, users don’t need anyone’s permission to safely get their funds back on-chain. It also allows for more flexible programmability of funds while applying those conditions to the base tier in the event of a worst-case unilateral departure. If one day you end up with something like OP_ZKVERIFY, progressing the state off-chain can effectively become a trustless process.
I don’t expect a concrete demo in the near future, but I think it’s definitely a sound idea and worth considering. This also shows that the wizard is doing more than just pumping out stupid JPEGs.