CHECKSIGFROMSTACK BIP 348 for Bitcoin Covenants

Welcome back to the second installment of our series where we’re taking a closer look at some really interesting covenant proposals that are gaining traction and are worth understanding in detail.
CHECKSIGFROMSTACK (CSFS), outlined in BIP 348 by Brandon Black and Jeremy Rubin, might surprise you – it’s not actually a covenant itself! As I mentioned in the first article of this series, we’ll also be exploring some proposals that, while not covenants, are closely linked or work hand-in-hand with them. CSFS is a perfect example to kick us off.
CSFS itself is a pretty straightforward opcode. But before we dive into the specifics of how it operates, let’s make sure we’re all on the same page about how Bitcoin Script, the scripting language of Bitcoin, works at a fundamental level.
Bitcoin Script is what we call a “stack-based language.” Think of it like stacking plates. Data is placed one on top of another on this “stack.” Then, to work with the data, the script pulls the top item off the stack, performs an operation (based on the specific instruction, called an opcode), and then often places the result back onto the top of the stack.
When a Bitcoin script is executed and verified, it actually involves two key parts: the “witness” (or unlocking script) and the script embedded in the output being spent (the locking script). The witness is essentially “pre-pended” or added to the beginning of the locking script. Then, each element from this combined script is processed one by one, from left to right, adding to or manipulating the stack. Let’s look at a simple illustration (the “|” symbol separates the witness from the script):
1 2 | OP_ADD 3 OP_EQUAL
In this example, first, the value “1” is placed onto the stack. Next, “2” gets stacked on top of it. Then, the instruction OP_ADD comes along. This opcode takes the top two items from the stack (which are 2 and 1), adds them together, and puts the result back on the stack. So now, the stack only contains “3.” After that, another “3” is added to the stack. Finally, we have OP_EQUAL. This instruction takes the top two items (both are “3” in this case), compares them, and if they are equal, puts a “1” back on the stack. Importantly, in Bitcoin Script, “1” can represent “True,” and “0” can represent “False,” in addition to their numerical values.
For a Bitcoin transaction to be valid, the script execution must reach a point where the very last item remaining on the top of the stack is “True” (represented by “1”). If it’s not true at the end, the script, and therefore the transaction using it, is considered invalid by the entire Bitcoin network.
Here’s a basic look at a pay-to-pubkey-hash (P2PKH) script – these are the scripts behind those older Bitcoin addresses that start with a “1”:
First off, in this P2PKH example, the signature and the public key are added to the stack from the witness. Then, the opcode DUP is executed. DUP simply duplicates the item at the top of the stack, placing another copy right on top. Next, HASH160 takes the top item (which is a copy of the public key), hashes it using the HASH160 algorithm, and puts the resulting hash back on top of the stack. After that, the `
How CSFS Works
CHECKSIG is one of the most commonly used instructions in Bitcoin. Seriously, almost every Bitcoin transaction, with very few exceptions, relies on CHECKSIG in one of its scripts. Signature verification is absolutely fundamental to how Bitcoin security works! The thing is, standard CHECKSIG is pretty rigid – it almost exclusively verifies a signature against the transaction itself that’s being processed. While you have some wiggle room to decide which parts of the transaction the signature applies to using different sighash flags, that’s about the extent of it.
CSFS is designed to change this and open up a new dimension of possibilities. It lets you verify a signature against *any* arbitrary piece of data, a “message,” that you directly put onto the stack. Instead of being restricted to just verifying signatures against the transaction itself, you gain much more flexibility. The CSFS opcode operates in a very simple manner:
To use CSFS, you first place the signature and the message onto the stack. Then, you put the public key on top of them. Finally, when CSFS is executed, it takes the top three items from the stack – expecting them to be the public key, the message, and the signature (in that order, from top to bottom). It then performs the signature verification, checking if the signature is valid for the given message and public key. If the signature checks out, CSFS places a “1” (True) on the stack.
And that’s essentially it! CSFS is like a more versatile version of CHECKSIG, allowing you to verify signatures against custom messages rather than just the transaction being spent.
What Is CSFS Useful For
Okay, so you might be thinking, “What’s the big deal? Why would I want to verify a signature against some random message instead of the transaction itself?”
Firstly, when you combine CSFS with CTV (which we’ll cover in more detail later in this series), you can unlock functionality similar to “floating signatures” that Lightning Network developers have been dreaming about from day one. The initial idea for this was to create a new type of sighash flag (the part of the signature that specifies what parts of a transaction are being signed). This was needed because in standard Bitcoin, a transaction signature inherently includes the transaction ID of the transaction that created the output being spent. Meaning, a signature is only valid if it’s used to spend that *exact* output from that *exact* transaction.
This kind of flexibility is highly desirable for Lightning Network. It could allow us to move away from channel “penalty” mechanisms. Currently, in Lightning, for every past channel state, you need to keep a penalty key and transaction ready. This is to prevent your channel partner from trying to use an outdated state to unfairly claim funds. If they try, you can use the penalty transaction to take all their funds. A more elegant solution would be to have a mechanism that lets you simply “attach” the valid current state transaction to any previous, attempted-theft transaction. Instead of confiscating all funds as a penalty, the funds would be correctly distributed according to the latest agreed-upon channel state.
CSFS, combined with CTV, can achieve this! You could create a script that takes a CTV hash (representing a specific transaction state) and a signature over that hash. This signature is then verified using CSFS. The beauty is, any transaction which, when hashed, matches the CTV hash and is signed by the corresponding CSFS key, can then spend the output secured by this script. Essentially, you can authorize future transactions by pre-signing hashes.
Another very useful application is delegating control of a UTXO (Unspent Transaction Output). Just like how a CSFS key can authorize spending any transaction matching a pre-determined CTV hash, you can also build scripts where other variables are checked. For example, you could check against a new public key. Imagine a script that allows a CSFS key to sign off on *any* public key. This signed public key could then be validated using CSFS and subsequently used for a standard CHECKSIG validation. This clever setup would let you delegate the right to spend a UTXO to someone else, without actually needing to move the UTXO on-chain until the delegated person decides to spend it.
Finally, when CSFS is paired with CAT (which we’ll also explore later in the series), you can build even more sophisticated introspection capabilities within Bitcoin scripts. However, it’s worth noting that as we’ll discover later, CSFS isn’t strictly essential for achieving these more advanced behaviors, as CAT alone is surprisingly powerful in this regard.
Closing Thoughts
CSFS is a really fundamental opcode that, beyond its own simple utility, becomes incredibly powerful when combined with even basic covenant opcodes, unlocking some genuinely useful functionalities. While the “floating signatures” example we discussed specifically mentions the Lightning Network, it’s important to realize that floating signatures are a generally valuable tool, applicable to pretty much any protocol built on Bitcoin that uses pre-signed transactions.
Beyond just floating signatures, script delegation is another broadly useful feature. It’s not just about delegating control of a UTXO to a new public key; the core idea is much wider. This ability to dynamically “sideload” variables into a script validation process after the script is created has incredibly broad applications. It’s not limited to public keys! Think about things like timelock values, hashlock preimages – anything really. Any script that currently requires you to hardcode a specific value to verify against can now become much more flexible, getting those verification values added dynamically later on.
Importantly, CSFS is not some brand-new, untested concept. It’s a mature proposal. It’s already implemented and has been running live on the Liquid Network and Elements platform (which shares Liquid’s codebase) since way back in 2016. And Bitcoin Cash has also had its own version of it since 2018.
CSFS is a proposal with a long history and a solid conceptual foundation, dating back almost as far as my own involvement in this space. With multiple, production-ready implementations already out there and clear, compelling use cases, it’s definitely something worth paying attention to.