There's a fresh BIP proposal going around called 'OP_CAT'. Ethan Heilman and Armin Sabouri are the ones who put the draft together. It's a simple change, only 13 lines of code, and it seems pretty straightforward at first glance. OP_CAT is all about concatenation, which means it's about joining or combining two input values into a single output value.
The OP_CAT opcode isn’t exactly new. It used to be part of Bitcoin’s script commands way back in the day, but it was quietly removed for safety reasons since Bitcoin was still in its infancy.
If you want to dig deeper into this BIP draft, check out these two links:
https://github.com/EthanHeilman/op_cat_draft/blob/main/cat.mediawiki
https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-October/022055.html
Overall, the effort-to-use-case ratio for OP_CAT looks pretty promising. There aren’t any clear downsides at this point, apart from the usual caveats. But keep in mind, we’re still just at the draft stage, and any actual activation in the Bitcoin network is probably still a ways off.
After Bitcoin added a limit (520 bytes) to the size of the element in the stack, there are logical arguments for reactivating some opcodes. OP_CAT is simple and easy to understand, and I see some people defending it on the grounds that it can be used to make Bitcoin is "quantum safe" by signing an EC signature https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-October/002201.html
So it is not to do new things but to enable some basic things.
What is the use case for this opcode? As in, a practical example where this would be helpful.
So far, the majority of items that are on the stack are hashes, signatures, and integers. None of which seem to have any clear deficiencies that could be solved by concatenating them.
The only thing I can think of is something like BitVM where you have bits as stack elements and this allows you to combine two of them together into (over several instructions) bytes.
There are many, read the whole "Motivation" paragraph for details: https://github.com/EthanHeilman/op_cat_draft/blob/main/cat.mediawiki#motivation
1. Unlocking a coin by signing a given message. Let's assume that you have "Hello World" message, and you signed it with some public key. That means, you can create an output script, that will push r-value and s-value of the signature separately, and then use OP_CAT, combined with OP_CHECKSIG, to require a specific r-value in your signature. Which means, instead of signing "this transaction", you can sign "this message" instead.
2. Doing Proof of Work to move coins. For example, you can split some hash into two parts: a target, and a tail of the hash. Then, after combining that with OP_CAT, you can run OP_SHA256 or similar opcodes on some data, and check if it is equal. In this way, you can for example move a coin if you compute 2^32 hashes.
3. Restricting ways of spending the coin by requiring a specific transaction. For example, you can trap a coin on a particular address, by requiring identical output script. Of course, in case of TapScript, that chain could always end, if you spend-by-key. But in some altcoins, it is possible to trap it directly by using Script. In general, it is just a consequence of applying the first point to "this transaction" as a message. Then, you can use OP_CAT instead of using sighashes, and exactly decide, what "transaction template" is accepted. Which means, you can for example say: "if you sign this, you can take up to 1 BTC from this output, and you have to put the rest in this change address".
4. Provably fair transaction puzzles, where the creator would not know the solution, without solving the puzzle. The spend-by-key path could be provably unspendable (as long as secp256k1 is not fully broken, but then spend-by-key can be softforked-out) for example if you put "x=1" public key as your TapScript key, and then put a TapScript, that requires mining N bits of the public key (probably non-zero, because of the half of the generator, or it could be relative to some other key than the generator, but this is harder).
in principle, OP_CAT can be used to implement so-called covenants, i.e. predefined conditions to whom a certain Bitcoin output can be issued. the recently introduced concept of BitVM to verify arbitrary calculations on Bitcoin would also be much easier to implement and more efficient with OP_CAT.
another very interesting possibility is to link the validity of a transaction not only to a valid signature, but to a specific valid signature, thus enabling effective protection for unconfirmed transactions.
1. Sign any message:
Input script: "<sigS>"
Output script: "<sigR> OP_SWAP OP_CAT <pubkey> OP_CHECKSIG"
Execution:
2. Proof of Work to move coins:
Input script: "<message> <tailHash>"
Output script: "<target> OP_CAT OP_SWAP OP_SHA256 OP_EQUAL"
Execution:
3. Transaction introspection:
Very similar as to point one. In the best case, it could be identical. In some other cases, it could require transaction building with "<txHead> <txData> <txTail> OP_CAT OP_CAT", and then hashing it with OP_SHA256. Then, you could set "<txHead> <txTail>" in your output script, but "<txData>" could be some part of the input, and for example represent some part of the transaction output amount, which can be changed by the transaction signer. Which means, if you for example allow picking three bytes in your <txData>, and it would be placed, where you have transaction output amount, then you can change the amount, and pick a number from 0.00000000 BTC to 0.16777215 BTC.
Some links, also from the BIP for OP_CAT:
https://medium.com/blockstream/cat-and-schnorr-tricks-i-faf1b59bd298
https://www.wpsoftware.net/andrew/blog/cat-and-schnorr-tricks-ii.html
4. Provably fair transaction puzzles:
Input script: "<signature> <pubkeyTail>"
Output script: "<pubkeyHead> OP_SWAP OP_CAT OP_CHECKSIG"
Execution:
Then, if you pick for example 0xbadc0ded as your <pubkeyHead>, then people could mine a public key, starting with x-value equal to 0xbadc0ded, and that would be a proof, that someone can break 32-bit public keys. Of course, any non-zero pattern will do (the only reason why zero will not work, is the half of the generator).
Interesting. For example, it could be used as a reward, to reveal the private key to some address, for example to 120-bit and 125-bit puzzle:
Input script: "<sigS>"
Output script: "OP_TOALTSTACK <puzzle120> OP_DUP OP_FROMALTSTACK OP_CAT OP_SWAP OP_CHECKSIG"
Execution:
It gets better. You can request generating some vanity address by some third-party in a provably fair way, and put some reward on that:
User input script: "<signature>"
Miner input script: "<pubkey> <vanityHead>"
Input script: "<signature> <pubkey> <vanityHead>"
Output script: "<vanityTail> OP_CAT OP_SWAP OP_DUP OP_HASH160 OP_ROT OP_EQUALVERIFY OP_CHECKSIG"
Execution:
Because we have Schnorr signatures, it is possible to do that in a provably fair way, without forcing anyone to pass any private keys. In the end, everything will be just combined, and <signature> will be just some 2-of-2 multisig, expressed as a single signature.
Also, instead of using OP_HASH160, it is possible to work on public keys directly, and request some vanity Taproot address in this way. But this is already covered in example "4. Provably fair transaction puzzles", because such puzzles are directly related to "vanity public keys".
But I don't see the OP_CAT bip on the repository file listing, there's only this pull request you linked that is still open. So doesn't that means the commit(s) haven't been merged yet?
To get an idea of what is going on in there, are you listing the Merkle leaf hashes from top to bottom and left to right, or are you putting them in another order?
For the merkle proof in the example, the json-ified inputs are:
You can see that there are 30 siblings in the merkle proof, so the merkle tree has a height of 30 (i.e the tree has a total of 2^30=1073741824 leaves).
Since the tree is of height 30, we first need to decompose the index into its 30 bits:
Now that we have the bits in the alt stack ordered in increasing significance (i.e, least significant bit is at the top of the alt stack), we can begin to check the merkle proof.
Currently, our primary stack looks like the following:
When we verify a merkle proof, we start from the bottom of the tree where our value is, and hash up the tree to the root, and finish by comparing our computed root with the attested root at the bottom of the stack.
Hope that helps!
Yeah, it really made things clear. But what do you plan on using this for in a Bitcoin script?
Is it going to be something like validating a previous block's hash for the purpose of starting a new protocol on top of Bitcoin?
Also, since this is TapScript, have you calculated how many bytes the witness stack would use on average? I'm going to guess that it will be quite expensive unless you set it to some fee rate below the purge level (as of now, 17.2 sats/vbyte).
Great point, yeah might get a bit pricy.
The main motivation for merkle proofs in my case is as a part of a trustless peg-out system/locking script for a zk layer 2 on bitcoin where we want to prove that, given a known withdrawals tree root (a public input of a zk proof), there exists a withdrawal for n bitcoin to a given address.
To solve issues around cost, the first thing that comes to mind is that it would be a mechanism of last resort.
Average users can buy wrapped BTC on L2 by having the seller of thew wrapped BTC lock their tokens on l2 for a period during which the buyer has to prove that they paid the seller on Bitcoin L1, with the knowledge that if they wanted to, they could always trustlessly swap back for bitcoin, and a few large liquidity providers would be the ones actually swapping between wBTC <-> BTC and likely charging a small spread to smaller guys who want to buy wBTC from them/bridge back to bitcoin.
the picture for Bitcoin's next soft fork is becoming clearer:
OP_CSFS, OP_CTV and OP_CAT are the covenants with the most support from developers. in my opinion, only features that extend Bitcoin's usefulness as money should be enabled, and use cases that harm Bitcoin's usefulness as money should be rejected.
https://en.bitcoin.it/wiki/Covenants_support
I don't see how this is the case. There's no consensus on any particular covenant implementation. In fact, it's clear that preferences vary and there is no choice that comes with no tangible tradeoff. OP_CTV is apparently the most preferable choice, but there are many who don't support it, just as OP_CAT, which is also very preferable.
As a money for what? Plus what other "non-money" features will OP_CSFS, OP_CTV and OP_CAT enable?
Because if it enables those features that would make it easier for people to use their Bitcoins on-chain to purchase an on-chain "artifact" like a dick pic or a fart sound, then that, I believe, has also extended its usefulness as a kind of "money", no?
Programmable money through extended scripts?