Home < TABConf < TABConf 2021 < Jeremy Rubin, Andrew Poelstra - Covenants (2021-11-05)

Jeremy Rubin, Andrew Poelstra - Covenants (2021-11-05)

Transcript By: Jeremy Rubin

Tags: Covenants

Category: Conference

Name: Jeremy Rubin and Andrew Poelstra

Topic: Covenants

Location: TABConf (The Atlanta Bitcoin Conference)

Date: November 5th 2021

Video: No video was posted online

As per Socratic village rules names of all attendees (other than the advertised speakers) have been anonymized and audio will not be published to preserve anonymity of the question askers.

The covenant concept


Shaun Apps (SA): I’ll kick things off with a bit of an introduction. Both Andrew and Jeremy will present. And then we will go through some questions and we’ll go to questions from the audience after that. So that’s the format for this.

SA: So, covenants. This term has historical context when it comes to religion and law. Many of us might be familiar with covenants within the bounds of property law constraining or bounding the use of land for example by covenant. But how many people here have heard of covenants as it relates to Bitcoin? Okay, good amount of people. So at a high level covenants provide the Bitcoin script introspection, such that you can constrain how an output will be spent by some predefined bounds. I’m not really sure how far back exactly covenants go. There is this seminal Bitcoin talk post by Greg Maxwell introducing the concept of covenants and providing a few amusing examples. For example, a Smashcoin covenant where spending the coin that covenant has to provide proof of an attack on an alternative cryptocurrency or even something like an adultcoin covenant, where the data provided would be someone’s date of birth, and it would constrain that recipient to be older than 18. Of course these are just amusing and silly and fun examples of the covenants concept and this is just a post in jest. However, there are some very exciting use cases for covenants which we will get into today. We have Andrew Poelstra and Jeremy Rubin, Andrew is going to be approaching covenants from the perspective of CHECKSIGFROMSTACK also known as CSFS. And Jeremy will be presenting on CHECKTEMPLATEVERIFY, referred to by CTV. So with covenants, there’s no one singular way of doing them in Bitcoin. There’s different ideas, different proposals, they each have their own trade-offs and use cases. So we will get into that. Andrew, do you want to go ahead and get started?

Andrew Poelstra (AP): So as Shaun says I’m kind of representing the CHECKSIGFROMSTACK school of covenants. I seem to represent a more general viewpoint. So to build on this idea of covenants, which by the way, I think does originate with Bitcoin talks thread… I’m not aware of any older discussion…

Jeremy Rubin (JR): Earliest I know.

Recursive and non-recursive covenants

AP: There are kind of two different categories of covenants that I’m going to call recursive covenants and non recursive covenants. I think that’s probably also the terminology that was used in this post. What a covenant is, is just a way to constrain where the coins are going. Using Bitcoin script you can determine under what conditions can a coin move, but once those conditions are met they can go wherever. A covenant lets you constrain that further and do all sorts of silly stuff like this. There’s a distinction to be made between non-recursive covenants and recursive ones, where non-recursive covenants let you constrain where the coins are going. Then you can maybe constrain it to be in another covenant which further constrains and so on. You’ve got to map out the entire future of these coins, you can only go so many hops but you’ve got to write out all of your constraints, all on the first shot. Whereas recursive covenants are ones where you can constrain the coins to go back into a covenant of essentially the same shape as where they came from. Thereby creating a sort of finite state machine that the coins can move between. Either they just stay in one place and some constants change or they can go to different states or they can come back around. You can create covenants the coins don’t escape from in this way. Even the way that I worded that, “don’t escape from” reflects the the danger inherent in this and reflects the fear that people have had over the years about enabling recursive covenants.

Different covenant proposals

AP: There have been a number of covenant proposals over the years. One of which is Jeremy’s OP_CTV which was previously OP_SECURETHEBAG. It has had a few names over its lifetime and it has gone through a few iterations. OP_CTV is designed deliberately to avoid recursive covenants, to avoid this entire specter of these horrible jokey but in some ways not jokey things. Whereas the other kind of well known covenant proposal that’s out there is a very general one based on these two new opcodes to Bitcoin called CHECKSIGFROMSTACK and CAT. There’s a more efficient variant of this where you directly add opcodes that can look at the transaction that is spending the coins. You can pull that onto your stack and your script execution and then constrain them directly. You’re sort of directly looking at the transaction that you’re spending, putting arbitrary constraints on those. In particular, if you put constraints on the outputs of the transaction that is spending your coin, that’s how you get these recursive covenants that just kind of permanently encumber the coins. There’s a trade-off between these two approaches. If you are trying to do something that avoids recursive covenants…. There’s a frightening history of covenants in Bitcoin, it is surprising that there aren’t covenants in Bitcoin actually. The nature of script is that it does have to look at the transaction. Bitcoin script has this CHECKSIG opcode which lets you check a signature on the transaction. The signature data of course has to be accessible to the script so that the CHECKSIG opcode can access it. But mathematically, the way a digital signature works is that is inherently tied to the transaction data itself. With some clever mathematical tricks you can kind of force a signature to go backwards and then get a hash of the transaction onto your stack and then start reasoning about it. In fact it is possible using Bitcoin’s CHECKSIG operator to say “This coin can only move if you provide a signature that’s just all zeros”. That’s a valid signature. There’s some metadata in there but effectively all zeros with a couple of 1s and 2s in specific places. You don’t contain the public key. Normally you say “I need a signature on the transaction with the public key”. Here you say “I need a signature with some public key on this transaction which has this exact form”. You do that and in order to satisfy the transaction you’re forced to provide a pubkey for which the signature will validate. That pubkey, it turns out will algebraically be a sort of weird mixed up hash of the transaction. You could therefore constrain what that hash has to be in your script and thereby get covenants. The reason this doesn’t work is that all the different sighashes in Bitcoin, except for one, actually cover the public key that has been signed. There’s a circularity if you try to do this. But if we had SIGHASH_ANYPREVOUT, which is a popular proposal for Bitcoin, then you would get this form of covenant. The point of this story is not to propose that as a serious covenant thing, the point is to demonstrate that it’s very hard to avoid having recursive covenants. So my position, this is not a debate, but my position here is basically we ought to have a very general, deliberately designed method of doing recursive covenants versus either trying to do something narrow, which first off you don’t get as much flexibility if you do the narrow covenant proposal. You still have to go through all the consensus changes and stuff, you get less of the benefit. But also because probably you actually do get recursive covenants. I bet you do, it is very hard to avoid it I guess. That’s me.

JR: I think most of that I would concur with up until maybe the conclusion. Drama makes perfect TV of course but there’s really not that much drama. I think Andrew and I maybe aren’t completely dead center in the Bitcoin community on this but we both think covenants are a good thing for Bitcoin. Where my perspective has diverged and what led to CHECKTEMPLATEVERIFY, which I’ll explain in a second what exactly that’s doing, was really more pragmatism in an engineering perspective. Getting this perfect primitive that gives us safe and expressive recursive covenants is pretty difficult. There are people in the community who are opposed to that kind of thing. So what I tried to do in coming up with CHECKTEMPLATEVERIFY was find that narrow, narrow band of protocol design that would be acceptable to even the most anti-covenant person. That is kind of what CHECKTEMPLATEVERIFY is targeted at. What’s the most limited thing that can actually solve some really interesting problems? I think this is something people get confused about, it’s not because I think the only thing we should ever do is this limited form, but it’s because I want something that is a part of Bitcoin’s gradual process of creating upgrades for Bitcoin. Rather than change the whole world all at once, maybe what we can do is we can get a simple primitive that introduces the ability to do lots of interesting things. We can grow around the tooling and infrastructure around building covenants based on that. And over time, as we learn more about what types of things people are trying to accomplish with covenants, we’re going to be able to make something that is sufficiently generic and usable for a wide variety of other use cases without introducing vulnerabilities or having to ingest a whole bunch of engineering work all at once to design the covenants framework for developer infrastructure, tooling, user interfaces, things like that. So for CHECKTEMPLATEVERIFY in particular, it’s actually really close to what Andrew described as “this complicated thing that you can do with the keys”. It is actually simpler, all it is is you pick the exact transaction that you want at the time that you’re spending to someone. So if I for example said that I am going to spend to this address and I want this address to send coins to 100 of my friends, that is an example of something that you could do with CHECKTEMPLATEVERIFY. What you’re committing to in that address is the exact transaction that it’s going to expand into later. Why might you want to do something like the one that I just told you? This is sort of one of the primal use cases for CHECKTEMPLATEVERIFY, congestion control. In my engineering process, the way that I think about these things, I want to pick a specific single use case that I want CHECKTEMPLATEVERIFY to absolutely nail and give a solid story for why you would want to use this, maybe a small set, and then design something that is going to satisfy that need. Then go back and see if there are other things that we can do. But I want to know that CHECKTEMPLATEVERIFY as a solution has good product market fit for this final user story. This example that I gave, where I split the transaction from a spending side to expanding side is really good. For example, if the mempool is really expensive, if you want to get a confirmation, you can get your transaction confirmed with just a single output but all your 100 friends can fully verify that they will with the expansion of that covenant receive their payment in the future. That can be really good for example for an exchange, that idea can also get expanded into much more sophisticated forms by leveraging some other things CHECKTEMPLATEVERIFY can also do, create Lightning channels without interaction. I think that generally, as you start going to the depths of what you can do with this very simple covenant, there’s even a kind of compiler that I wrote for Sapio. It does CHECKTEMPLATEVERIFY based smart contracts. That can be used to make all sorts of really wonderful covenant based things. The compiler itself is generic to future types of covenants that might be defined. If somebody comes along and says “I’ve invented a new form of covenant” we have a chance to develop tooling that can be used in the future when we have expanded types of covenants. That’s sort of the perspective that I have. From where we are now, I don’t know how long it would take for us to get this grand vision of sufficiently general covenants, Andrew might claim you just need CHECKSIGFROMSTACK but those covenants are really, really large in size, the expansion of them onchain is really expensive. CHECKTEMPLATEVERIFY ends up being, because of its simplicity and this ahead of time compiling notion where you have to know where you want to send it, it ends up having a really low chain footprint. It very difficult for even mildly more sophisticated covenants to beat a CHECKTEMPLATEVERIFY based covenant in terms of onchain efficiency. It is a little bit like somebody asked for a bridge. There’s a river that we want to cross to have covenants and what I did with CHECKTEMPLATEVERIFY is I cut down a tree and I just plopped it over the river and I said “You can walk across this”. My feeling is a lot of developers are like “Well no, we want to carve an ornate bridge and it is going to take time”. I’m like “Here’s something that we can get across the river today with and maybe we can then use that to build more efficiently, for the future we can build from both sides at the same time or whatever”.

Footguns when designing covenant proposals

SA: Just a reminder, as we ask questions the audience is free to respond to those questions as well. Could you guys talk more about what’s the specific parts of a transaction that have these footguns when you’re designing covenants. What are the parts that have the most careful consideration where things could potentially go wrong?

JR: I think basically all of it, if you mess up any detail of a transaction you’re kind of screwed. So one of the things that’s kind of a footgun in CHECKTEMPLATEVERIFY for example, is if you send the wrong amount of money to a covenant, this is also a problem for any covenant, if you make a covenant that expects to have available to it 1 Bitcoin and you send 1 Bitcoin minus one satoshi, that whole covenant might not be able to execute in the way that you expected. That is one area that is a massive issue for anybody working on covenants. Another big problem is, I have somewhat of a solution for it, but it’s not that popular yet in the community. Paying fees, if you have a covenant you’ve restricted the coin to only be spent in very specific ways. How are you going to assess the fees? If you have to pay more fees than you expected then maybe you’re going to drain the amount of money the covenant expects too far and then it’s not going to execute correctly. So paying fees is also an area where it’s really tricky. My general proposal for solving that, which is maybe a little bit out of scope for this, is that we should build a way that fee paying can can just be completely separate from transaction flows of execution. Where your covenant and whatever other smart contract code, maybe a Lightning channel, just executes as the transaction graph you want and fee paying happens as an external consideration to that.

AP: Regarding specifically the fee issue, I don’t think we should get too mired in the details of that. But I think there’s maybe a way using child-pays-for-parent (CPFP) that would be less dramatically different from how transactions are structured. But to answer the original question on the most dangerous part of the transaction, some parts are less dangerous than others. Whatever output you’re constraining with your covenant, that’s the dangerous part. As Jeremy suggested you could constrain your output to be something that’s impossible. It has to have a certain value that you just cannot get when your transaction is structured the way that the covenant requires it to be. You could also make it impossible to spend in ways where your output to be then spent would require you construct a script that violates some limit that will be too big. Or would otherwise step outside of the balance of scriptSig. Maybe you have to add two numbers, they wind up being larger than 32 bits or something like that. Under some weird state that your covenant can get you into you can just find surprisingly that your coins are unspendable. Even if you can see it coming, the covenant is kind of forcing you to drive that way. The outputs are the most dangerous. There’s some other parts of the transaction that you could restrict with covenants. You could say the locktime has to be a certain minimum height. Even if you screw that up, then you have to wait until the minimum height has been achieved. I guess if you screw it up such that it’s like years or decades in the future that’s not much consolation. But at least in principle it is recoverable. Or if you require the transaction version number be something weird and non-standard well, those will still be accepted by the blockchain, you’re then going to have to go to a miner directly because transactions at that version number won’t propagate but it will confirm. Stuff like that with sequence numbers for your inputs, they may constrain your replace-by-fee (RBF) behavior or whatever. But it’s really the outputs. When we talk about covenants we really are talking about constraining outputs, even though in my mind it is a more general constraining the shape of the transaction. Ultimately to get cool applications and also dangerous applications you have to constrain the outputs.

JR: I’ll just add that my interpretation is that outputs also includes inputs to the transaction. There are some really surprising results that you can get where if you have a transaction that has two inputs, you can have both of them constraining that the same outputs get created. And so you could have two inputs and they’re both saying create an output with 1 Bitcoin and they’re both satisfied by the same output. Then you lose half the value in two different covenants. So there can be some sort of surprising interactions between how covenants can work and that’s why at least for the time being my path with CHECKTEMPLATEVERIFY is lock it down as much as possible so we can build things that we know kind of work. Then the more surprising, harder to get right things we can get all the sophistication around that over time.

Impact of covenant proposals on Layer 2 protocols

SA: Jeremy you mentioned one of the use cases being congestion control. Can you guys talk about these proposals with regards to how covenants would affect Layer 2 solutions, like the Lightning Network? What’s to be gained from these proposals? How can it improve things and what can it do?

JR: Layer 2 with covenants is amazing. Right now Layer2, uh whatever. Layer 2 with covenants? Awesome. There are a lot of problems in building layer 2s. Don’t get me wrong, I think Layer 2s are a good solution for a wide number of problems. That spans Lightning, sidechains, whatever. The way that I like to think of it is Bitcoin and lthe blockchain is executing as like your CPU and Layer 2 is executing as your operating system. This has given you new capabilities at the base layer, your operating system can really take advantage of these new instructions in ways that are really great. One example that I like for the Lightning Network is creating channels, it’s kind of hard because you have to have both people online. If you want to get a channel out of Coinbase what you’d have to do is you’d have to withdraw your funds from Coinbase first, then you’d have to make a channel with somebody. What if you could just say “Coinbase, please make a channel for me” and then go offline, Coinbase sends you a channel later. There’s no trust assumption with Coinbase, that would actually be pretty impactful for getting more liquidity onboard. That’s one area that congestion control is also really relevant for Layer 2s. Let’s say you wanted to create 10,000 channels all at once. Right now you have to consume a lot of block space to do that. With CHECKTEMPLATEVERIFY or other covenants you can defer that chain load and you can do it lazily whenever you need to close the channels. If you’re opening a channel and you don’t expect to close it, that could be like a year later that you’re actually closing it. That could be really impactful for onboarding more. Then also for exiting. In the case of certain sidechains you might have to pay out a large number of users, I think Stacks had something where in their consensus protocol they expected to pay a certain number of users and they couldn’t get their transaction confirmed. They had kind of a consensus fault as a result. With CHECKTEMPLATEVERIFY your Layer 2 sidechain can be agnostic to the underlying mempool weather. You can just always pay a very high fee for your single output transaction and lazily let people get their things out. It also helps a lot with, we can dive into any of these, but with custodial issues and that’s for Layer 2s or for individuals. Blockstream, which is a fabulous company, had a bug a while back in their Liquid federation where you deposited funds into their Liquid custodial service and the funds were supposed to move every couple of weeks in order to keep the timelocks fresh. If you had covenants you would eliminate that need to move the funds. Now because they have this constraint, there was a service that was supposed to be running in Liquid that made sure that the coins were moving frequently enough that the timelocks guaranteed that this failover condition wasn’t happening. That service wasn’t running correctly, Andrew can probably explain it but it is maybe out of scope for this. That guarantee was violated. Covenants would fix things like that where you could express a little bit more logic about actions that have to happen constructively rather than automatically guaranteeing the flow of things. And also those types of deposits. You could have actions where the funds automatically maybe even are returned to the depositor instead of just failing over to a different signer. So there’s a lot of really exciting things that covenants would brings to Layer 2s that I think we should all be excited about it if it happens.

AP: That’s a really good answer. Specifically about that bug, the issue was the coins have to move every 2 weeks and the timer was set at 2 weeks which is not correct. You can’t react instantly on the Bitcoin network. You can’t create transactions and expect them to be confirmed within the next block. You’d have to spawn a new block once the timer came up. We’ve changed the logic to sweep the coins a bit earlier than that. I think we do like 300 blocks early or something. But this is a really good illustration of where covenants would help because it’s kind of adhoc. a) It is is annoying and expensive to have to sweep all these coins all the time. b) When you’re dealing with signatures and timelocks hoping that miners will accept your stuff in a timely manner, that’s also a very frustrating. You can’t guarantee that it’s going to work and this leads to embarrassing bugs like this that were noticed by people on Telegram. To build on the first half of what Jeremy was saying where you could in principle have coins that are just sitting there waiting for Coinbase to do their part of opening a payment channel. You can generalize that. In a lot of cases you don’t care that it’s Coinbase, you can say “Anyone who has enough channel capacity and who is able to connect to where I’m actually trying to send coins to, anybody can just come pick this up and open a payment channel”. You can offload a lot of the normally online interactive stuff that you’d be doing with peers you have authenticated connections to. You can sort of formalize what your requirements for those periods are, drop some code on the blockchain and then just wait for somebody to pick it up. I’m glad that you had such a cool answer. I think of covenants as actually not so much about Layer 2, I think about vaults and custody and stuff. But that’s a really cool set of applications that I don’t usually think about.

SA: Want to field some questions from from the audience?

Vault applications

Q - I’d love to hear more about your thoughts on vault applications.

AP: What do I think? I think that vaults are necessary for major Bitcoin adoption quite bluntly. So what vaults are is they are a covenant construction where you can constrain coins such that they cannot be directly moved to any particular destination. They’re kind of sitting in this covenant script and if you want to move them somewhere then you have to create a new transaction which defines the destination, move the coins to a staging area and then after like 3 days or something the covenant logic will then allow the coins to be moved to that destination. During this 3 day waiting period anybody with the appropriate key can basically reset the timer or they can change the destination if they want and in doing so they reset the timer. The idea here is that if your keys somehow get out of your control, somebody steals your keys or something, they can’t run off with your Bitcoin. They can try and then move the coins to this 3 day timer. You can keep resetting the timer on them and then the two of you will have a fee war. If your attacker’s goal is to deny you access to your coins they can do that as long as they’re willing to stay online and continually spend money to sustain this attack. But they can’t get the coins and run off with them which should discourage the kind of expensive attacks, we would be required to extract key material. Related to vaults, even if you have control of your own keys you may want to limit how quickly the funds can move. Maybe these keys are constrained by an external legal thing, maybe they are company coins and your charter doesn’t allow you to spend too many of them at once. Or maybe you have some cold keys that you have in deep storage. The hot keys muggers might take and you want those hotkeys to only be able to move coins so frequently. You can use the same vault construction to say that the coins can only move after a certain amount of time and in a certain quantity. In Bitcoin if you authorize the coins to move then any amount of them can move to any destination. It is really binary. Either the coins don’t move at all or it is a free for all and that really scares me as an individual trying to custody Bitcoin. If they were like State Street or somebody trying to custody a tremendous amount of coins then that would really frighten me. I think this is necessary for Bitcoin to get serious adoption and hopefully we get there.

JR: I like vaults, CHECKTEMPLATEVERIFY can do a slightly different variant of them but also meaningful. One of the properties that I think is most relevant for the type of vault that I’m doing, it has a failover where it’s basically a lukewarm wallet. You have your hot wallet which you can spend however you want discretionarily, you have your cold wallet which is really difficult to access. You went to three different deserts and buried your metal plates with your seed and you’ve got to get two of them to recover. It is buried under concrete and there’s like radiation or something. We were talking about that the other day. You have this really difficult thing. Imagine you’re like “I’m going to withdraw, I’m going to put my funds onto that 2-of-3”, you’re never going to get those coins. That’s an emergency procedure. You can model your backup procedure as you’re leaking entropy every time you access it. Every time you go to do your procedure somebody can be watching and be like “Now I know where Andrew keeps his thing”. Also the other side of that, the more difficult it is to do the less regularly you want to do it. Your desert might become 3 different drawers in your desk, it might get degraded to that level but you might be willing to pay a one time cost for that. You might say “Casually whenever I’m visiting a new city take a GPS and bury something somewhere and just have a key stash randomly”. What you can do with this lukewarm wallet concept is you can set it up such that your funds have an annuity. Let’s say you have 10 Bitcoin on it, once a month you have the option to withdraw 1 Bitcoin out of this contract from the last time you withdrew. You’ve got this stream of liquidity that you can get out of your vault. But if you ever get hacked you have the ability to emergency subvert it back to that deep cold storage. What this is doing is it’s separating the concern of your backup from “I want my funds to be safe and secure” to “spendable and also I want to be able to recover them in emergency”. By separating those out nicely I think that that can really help a large amount of users adopt higher security cold storage backups.

A proposal to reenable OP_CAT

SA: Part of the discussion around covenants is the reintroduction of an opcode. that was disabled by Satoshi in 2010, referred to as OP_CAT. Could you guys talk about how that would affect these covenant proposals? What are the things that are gained from that? How does that play into these covenants?

AP: OP_CAT is my favorite opcode. CAT is short for concatenate. What OP_CAT lets you do is you have two objects on the stack in your script interpreter environment and you just stick them together. Now you have one element that is the first thing after the other. In the context of Bitcoin where execution is verification you can also run this backwards. If you have some big object you can split it into two by asking the user at spending time to provide the two pieces. You CAT them together and check equality basically. You can always invert every operation this way. With CAT by itself you can break apart signatures. Algebraically a ECDSA signature or Schnorr signature, there’s two different pieces, a numeric part that we often call s and a public key that we call R. Without OP_CAT if you’re trying to do funny covenant tricks like sneak covenants into the protocol by finding algebraic backdoors then it’s difficult to constrain your signature if you can’t break the signature part and constrain s independently of R. They’re structurally very different things and R is much harder to constraint. In Taproot where we have Schnorr signatures using OP_CAT and the Schnorr signature verification opcode it turns out that it is possible to get a form of non-recursive covenant where you literally get a transaction hash. Not even like a funny mangled transaction hash but a literal SHA2 hash of all the transaction data onto the stack. I don’t want to get too algebraic but this is pretty cool so i will. The way the signature signing equation works is that you have the s value equals k plus your hash times x where k is a sort of ephemeral secret key and x is your real secret key. Using covenants and CAT you can restrict k to be equal to 1 and x to be equal to 1. Now that equation reduces to just s = e+1 equals equals one. You can’t really do arithmetic on big numbers in Bitcoin but with CAT you can by breaking big numbers into small ones. What you do is you take this signature, you’ve constrained it so that your s value has to equal the hash of your transaction plus one, you can use CAT to pull the lowest order couple of bytes off of that s value and then you subtract 1 from it using ordinary opcodes and then use CAT to put it back. Now you have a SHA2 of all the transaction data. You then request the user put the explicit transaction data onto the stack, you use the SHA2 opcode to compress that and check equality between the one that you stole from the signature and the one that the user created with explicit data. Now you use OP_CAT to pull apart that blob that you just hashed into the constituent transaction parts and now you can constrain them. Now you have covenants and all you need is CAT.

JR: If it makes anyone feel any better I half-followed that. You have to read the blog post to really work through it. The way that I described CAT is that it’s kind of like the scrawny 80 pound kid who gets picked first for basketball because he or she can sink three pointers every time. You’re like “Where does that athletic talent come from?” CAT also makes Bitcoin weirdly quantum secure, you can get Lamport signatures in. Did you know that one?

AP: I forgot that one.

JR: There’s all these random things. If you have CAT you can also get a CHECKSIGFROMSTACK variant with that. There’s a myriad of things. I think that’s also a good example of what Andrew saying earlier, probably we’re going to accidentally get recursive covenants at some point because CAT is this low power thing that introduces crazy amounts of complexity to Bitcoin. The power comes from the most surprising places.

Q - How do you split with CAT?

JR: You turn it into a verify opcode that verifies that the concatenation of two things you pass into the witness are the split of that thing.

Q - There’s going to be huge signature data?

JR: Yeah it is a theoretical possibility. Then it is sort of some code golf to get it down in size.

Q - Why did Satoshi originally disable CAT?

AP: The original implementation of CAT had a memory blow up issue where it didn’t constrain the size of its output. You could push the zero byte or something and then use OP_DUP to duplicate it and CAT to put them together. You just use DUP CAT DUP CAT DUP CAT and then very quickly my hands will be on other planets. That was why it was disabled. If it were only OP_CAT that was broken and only in this way I think we probably could have just fixed it properly. It would just be a soft fork to say that from now on you’re not allowed to CAT things that are too big. It was part of a larger project to audit all the opcodes. There was like a dozen of them disabled that all had individually small issues that reflected a need to step back and reassess. Satoshi decided to just unilaterally disable them all. At the time I think no one was really thinking about the difference between a soft fork and a hard fork, the difficulty of adding things versus removing them. The language around it was like we could disable and reenable them in the future. But really they were just removed. They just had names in the codebase. That was the reason for CAT, the memory blowup.

Q&A

Q - Can you help me visualize where the code for calculating the program lives?

JR: It depends on the covenant proposal. For a generalized one the covenant code would live inside of the script basically. Then you would also have some logic for the creator of the script path for how to create satisfactions of that, how to produce witnesses and transactions that meet those requirements. That code might be more complicated than the verification code that’s inside the script itself. For CHECKTEMPLATEVERIFY in particular it’s the extreme version of that where all you know is transaction hashes. You have to have all of your logic for how to treat those and when to broadcast them and other things you might do as a separate representation that you’re maintaining yourself.

Q - Very simply in the same place where you might see a multisig script there’ll be an equivalent sort of script that has various constraints on it which are more advanced.

Q - But how would a new transaction be triggered?

JR: All of the logic for driving it forward has to be user generated. They’re not self executing. They could be if somebody submitted a transaction but there’s no code in Bitcoin for saying “By consensus this transaction has to emit another transaction at this time.”

Q - The recursive covenants, I guess that’s a little more complicated. The question would be that same script transfers along with…?

AP: Yes exactly, the user has to take action to move the coins but the only action they’re allowed to take is a movement of the coins to another copy of the original script basically. So the covenant will constrain your actions but somebody has to take a positive action.

Q - Could there be multiple scripts that satisfy the same covenant?

AP: The short answer is yes. Covenants don’t have to be constrained so narrowly. You can say a coin is allowed to move to any number of specific scripts. You can say the coins have to move to any script as long as it starts with some specific condition. After that it can be a free for all. Depending on the exact covenant construction, but in principle you have complete computational freedom here.

Q - On the application layer, I know about the research into the idea of coin pools. Say I have coins, I dump them into what would be a trustless escrow along with a hundred other people. That UTXO progresses block by block as people spend funds. Maybe there’s somebody who’s running this submarine swap server and can get funds up on the Lightning Network. Kind of like the architecture Green wallet uses right now without covenants. One of the downsides of that is the transaction graph can kind of explode? I’m curious for your thoughts on how that’s going.

JR: Yeah so they’re possible. There’s also some other covenant opcodes that have been introduced recently. One is called TLUV (TapleafUpdateVerify). I think coin pools are a really good opportunity. They kind of necessitate some sort of reputation layer which I think Lightning also has some of this concern. You don’t really want to be in a coin pool with people whose phones are always off. You need to know that whenever you ask for a transaction and the transaction satisfies your higher order business logic of “This person is requesting to send money, that’s one of their balances” you just by default sign it. You do want that liveness guarantee for the participants. But those actually would keep the transaction graph small because people would share UTXOs. The different proposals for it just have different trade-offs. I think people should largely ignore transactions and only think in bytes because sometimes you’re like “This way of doing it has fewer transactions” which I think is what people feel with TLUV. They’re like “This only has exactly N transactions whereas CTV would have like 1.2N and it’s worse.” But if you count the bytes CTV is like six times smaller. So for some of these things it can be surprising when you do the transaction counting vs byte counting, smaller transactions versus larger, fewer ones.

Q - Would the liveness requirement apply to everyone in the coin pool or would it be possible to have a quorum where some folks have to be live?

JR: Whatever guarantee you want. You could imagine that you have a pool where everybody has a buddy and you say “I trust that my buddy or someone else is going to be honest”. Then you could do like a half threshold on it [note: e.g. AND(OR(Key(A),Key(B)), OR(Key(C),Key(D)), OR(Key(E), Key(F))), any group of N/2 buddies]. That would let you do some more sophisticated stuff. They would be able to steal your funds though. In the CTV world, the way that I think about it is that as soon as you have a fault, you want to split your pool in half. So if your pool has a liveness fault, you split it and then if there’s one person who’s offline, then half the pool is back online, and then the other half has to split again. You can do the math. With two transactions, now we’ve got 75 percent of the pool back online. Then with another one you get people back online pretty quickly. That unfortunate person who was in the tree very close to the offline person has to do O(log(N)) transactions to exit which is still not that bad. O(log(N)) is pretty small.

Q - For context, the reason why I ask, as we’re seeing the Lightning Network grow a lot of the scaling that we’re seeing is multiple users to one node but where multiple users don’t have keys onchain. Multiple users of one channel, it’s not ideal and nobody’s really happy with it. But the really interesting thing Green wallet does, they have multiple users that have keys onchain and it’s still one node, the node is just doing submarine swaps from onchain to offchain. Scaling that model and making it to where they can do many users and it’s not a requirement [uintelligible] for being distributed among the pool is a very interesting idea.

JR: The other thing I wanted to add too thinking about this in terms of Lightning, it is a benefit of CTV over the TLUV style, without adding ANYPREVOUT into the mix, a CTV based coin pool would be compatible to having nested channels. All of these things, you’d only have to do an update when you have to rebalance liquidity or make an external payment. Otherwise you can just be doing everything in your leaf nodes as Lightning payments. I think that’s a pretty powerful composition of primitives where you can create a channel with a bunch of people and then only have to update it occasionally.

SA: Time for one more question.

Q - Question for Andrew. Do you see the downside of CTV just being basically that it brings to bear the review process of something that’s too limited or you actually see some more problematic failure modes?

AP: No, it is basically just that it’s essentially just too limited in my view. It was a slightly related point that if we find in the future that there is a cool application for more general covenants, because we have like 90 percent of the functionality already in CTV it would be a harder sell to then come back and do it again for an extension. Also in some cases there’s a possibility that CTV could somehow be incompatible with something that otherwise would be a future proposal. Or there could be an efficiency or some sort of interaction there that will be complicated to reason about. Essentially if we’re going to get new stuff into Bitcoin I would prefer to get the most general thing that we could. I suspect that our disagreement is really what is the most general thing that we could? I think Jeremy has expressed skepticism that that we could actually get all my stuff into Bitcoin even if I proposed it properly.

JR: Just from the community’s perspective, there have been people, Shinobi has stated publicly that he will not accept anything more complicated than CTV. I don’t agree with that as a position or think it is good, but he has his reasoning and the community is a harsh mistress. I don’t know if we can actually get everybody on board with something but I like to try and even for CTV it’s hard to get people to “get activated”. There’s utxos.org/signals for people who have reviewed it sufficiently and feel like they could get behind getting the community towards a merge and release and then activation. That’s going okay but it’s not a snap of a finger, it’s like a multi-year effort to get everybody feeling like they’ve reviewed it enough and it is getting enough of a use case they care about over the line.

SA: We’ll go ahead and wrap up. Thank you guys both for for doing this.