Explaining Miniscripts with Andrew Poelstra

Andrew Poelstra (Blockstream)

[00:00:00] Andrew Poelstra: Hi everyone. My name is Andrew Poelstra. I'm the director of research at Blockstream and I am here to talk to you today about miniscript, the project I've been working on for a couple of years. I'm going to give up high level picture of what miniscript is and what it means for the future of Bitcoin as we go into this new era of reduced block rewards.

Alright? Miniscripts, safe and standard wallets.

So, before I talk about miniscript, let me talk a little bit about addresses. These are something that have been with us since pretty much the inception of Bitcoin; was generally considered to be a very standard thing. In fact, obviously addresses have changed very few times, since, well since forever we've had these sort of "1-style" addresses. In the very early days, in 2009-2010 these had a bit of a slightly different meaning than what they do now, where rather than representing the [00:01:00] hash of a public key, they just represented a raw public key.

But other than that change, which are the very technical kind of user invisible change, and one that happened long before Bitcoin had much of any adoption is one addresses have been with us. They've meant the same thing. Perfect. Pretty much all of the last 10 years. And what they represent is a public key, an elliptic curve point that represents a signing key that users can use to move coins. Now we normally think of Bitcoins as being controlled by keys, right? But Bitcoin is capable of a fair bit.  In particular. It can do multisignature you can have multiple keys that are needed to move the coins. It can do, they can check Casper images. This is something that's used for like lightning HTLC is to ensure that multiple payment channels can we chained together. It can check time locks. It can make sure that after a certain amount of time, if some keys are unavailable and different ones become available or something like that.

[00:02:00] And because these 1-style addresses, they look like a whole pile of random letters and numbers, basically what they represent as a single key. They don't have the expressivity to talk, to describe anything more than just a single key. To get this extra functionality, we have a different address type.

You sort of have three styles of addresses what are called P2SH for "pay to script hash". These are introduced in BIP16 way back in, Oh, I'm going to say 2012 it might've been 2013 of a way to give a standard address type for more advanced usages of Bitcoin.

And then later in 2016 was the advent of SegWit, we've got this third address type is BC1 addresses, and these are functionally basically the same thing as was the old style 1-addresses or the 3-addressess with a couple of cool new changes.

One is that you can see they have a very different format. BC1 - you can see the letter of the different, there's no longer any capital letters. Easier to distinguish [00:03:00] things. The addresses are a little bit longer, and the reason for this is that these addresses have a better error correction code. Or I should say "they have an error correction code" on them. So, if you make a typo in a SegWit address, it's guaranteed that's going to be detected.

The old style, I just have what's called the checksum. So, if you make a typo, there's a very high probability this will be noticed, but in theory it might not be. You could just send coins to a bad address, and even if you notice that there's a problem, you can't figure out how to correct BC1-addresses to give you these capabilities.

The second thing that BC1-addresses to give you is future proofing. That is, whenever changes to Bitcoin script happen, now we're in the future, we can use the same old BC1-addresses any, any software that's able to support these BC1-addresses is able to just keep working.

Okay. So, since we developed this, add this type, more or less, we don't need to be changing our address formats anymore, no matter what's happening in the underlying technology.

[00:04:00] So. Addresses are great. They're very stable. We're talking over 10 years now, and then we've only got these three iterations. But, behind these addresses are keys, as I mentioned. Behind some of these addresses are scripts are more interesting, more rich, information that describes multiple keys that describes timeline, that describes hash pre-images and, underlying all that, there's more or less no standardization at all.

I'm going to talk a bit about why that is. And I'm going to talk about miniscript, which is a way to solve this problem. And I'm also going to talk about why that is a problem. It might not be obvious.

So, let's take a look at what a Bitcoin script looks like. Here the script is doing something nontrivial. And to illustrate the point I'm making; I'm going to say I don't remember what this script does. You can see as a whole bunch of opcodes in a row.

If you were to use this script on the Bitcoin blockchain, the way you would do so is by hashing it up, you would get an address, it would be one of the three addresses or probably a SegWit BC1-address.

You'd be able [00:05:00] to share that with other people, and no matter what wallet software those people are using, they'd be able to send to your address. So, on, on the sending side, everything's great. There's no question of interoperability, but for your wallet to recognize those coins, for it to receive those coins and for it to later spend them, your wallet needs to understand the script. It needs to know what keys are involved and needs to know how to talk to a hardware wallet to look up those keys. It needs to know how to get signatures. It needs to know in what order to put the signatures. It needs to be able to estimate how many signatures and how large they might be in order to do fee estimation; it has to do a whole lot of work.

And when you're generating new addresses, it has to do this all again. It has to generate a new script like this, but where some of the constants have changed and so forth. And what that means is that as a wallet developer, you wind up doing, if you're trying to do anything non-trivial, if you're trying to do anything outside of the one key one signature, one Bitcoin kind of model, then you need to write a lot of code that handle complicated [00:06:00] scripts.

And you need to more or less do it on your own. You don't have off the shelf components. You can't use other people's wallets as a base or as something to interoperate with. Because if you're doing anything different from what other people are doing, you're stuck using this script.

And the problem here, you might think, well, if you're a wallet developer, this is your job, right? I mean, you have to deal with the complexity of the Bitcoin software and the Bitcoin networks so that your users don't have to, so your users can just see these addresses, spread them around. The problem is the Bitcoin script is really not well suited for the kind of questions that you need to answer to be a wallet developer.

The Bitcoin scripting language is designed to be run inside of Bitcoin core. It's designed to be run on Bitcoin nodes whose role is to verify that the coins are being spent legitimately. And when you're running the script, you're basically just hammering through a bunch of op codes. The script interpreter doesn't understand that are keys involved, that doesn't [00:07:00] understand that they have a spending policy. It doesn't understand that the idea behind the script is some sort of representation of the rules under which coins are allowed to move.

What the script interpreter sees is a whole bunch of opcodes that it just needs to apply on the execute one after the other, and, as a user or developer, you care that it's not going to execute the wrong thing. You care that there's no ways in which somebody can feed it that data and steal your coins. You care that if you have the right keys available that you can actually spend the coins. You care about how big your transaction is going to be. You care about a lot of stuff that the script interpreter doesn't understand.

And the problem is you're writing stuff in the script, you're writing stuff in the interpretive language. So, this is a large part of the reason that there isn't really standard tooling for doing interesting things in Bitcoin script because the interpreter model just doesn't let you do things. It requires a lot [00:08:00] of human ingenuity and ad hoc techniques to translate from the interpreter's language to the language of people.

I'm going to drop down and show you an alternate description of the same script of the script that I just showed you and this here you can see there's a lot of noise. There's still a lot of stuff going on that is clearly something that matters to the script interpreter and maybe not to user. But you can also see I have visual representation here and you can kind of tell what's going on. This represents a spending policy. This represents the rules under which coins might be spent.

You can see at the top level I've got an "AND" and what that's telling us is that both of the two branches under the "AND", both of those policies need to be satisfied in order for the coins to move. On the left side, we can see there's an "OR" that means that one of the two things below it need to be satisfied to spend these coins.

You can see, so either it looks like there's a public key, pubkey #1, so either you sign this pubkey #1 or your SHA256. That's a hash, [00:09:00] or you need to provide a hash pretty much. So, either public key #1 signs or you reveal hash preimage and then also whatever's going on on the right side.

So if you could represent script in this way, and I'm just telling you with miniscripts you can, as another wallet developer if you're worried about how to guarantee that coins can only be spent under the conditions you want and that they can be spent under all the conditions you want, this suddenly becomes a very easy question to answer in a very general way. Kind of, no matter what policy your user wants to build out of "ANDs" and "ORs" and thresholds and signature checks and time locks and so forth, they're able to construct something like this and it's possible for general purpose software to just run through the entire thing and reason about it and determine exactly under what conditions the coins will be spent.

Under each of those conditions that can determine what signature they needed, what order they need to go in, how to move them around, how to estimate the size. All these kinds of cool questions suddenly become straightforward to answer.

Okay, [00:10:00] so let me kind of summarize the kind of problems that we have using bitcoin script, and there's sort of two big, big categories of issues that we have. One is for individual wallets, we have this issue of key management: when you're trying to graduate from this single key world to a world where you have multiple keys because maybe your user wants to be able to store multiple keys all over the place, or they want redundant keys, or maybe they want backup keys that are stored with their lawyers or with their families or something. Or maybe the user is doing something multi-party. Maybe the user is working with an escrow agent. Maybe they're working with a wallet like Blockstream Green or Casa or something, which it was a split cut custody wallet where you have a counter signer, making sure that your coins are only moving under the right conditions. Maybe you're moving coins into a lightning payment channel. Maybe you're moving coins into liquid. Maybe you're moving coins into some complicated scripts that it's not widely deployed yet. Maybe you're doing some of your own ad hoc kind of [00:11:00] thing.

As a wallet developer trying to support this diverse set of use cases, you have to know, first of all, what is a script that expresses this use case? That's quite a complicated thing to answer. Given that, how can you argue with security? How can you argue with correctness?  How can you convince yourself and your users that the script you came up with is actually a reasonable script for this policy?

And then assuming you can get over that hurdle, which typically involves months or years of software development was Bitcoin experts, then practically when you're using a script, you have a difficulty. How do you work with hardware wallets? What keys do you need? What do you need to tell the hardware wallet to get the right signature, though?

And then, if you can answer that question, well then what is it going to cost once you've got the signatures? What order do they go in? Do you have to add extra metadata? Do you have to have hash pre-images? You know, how can you estimate the size of the transactions you're producing both in the average expected case or in the [00:12:00] worst case.

Those questions are very important for fee estimation, right? As a wallet, you have to come up with a fee. If you overshoot, your users not going to be too happy because you're wasting money. If you undershoot, your user's not going to be too happy because the transaction won't get confirmed. Right?

So, all of the other questions that right now, while the developers have to solve on their own, and miniscripts give us a general framework in which no matter what complicated policy you're trying to implement, you're able to answer these questions. And in fact, you're able to answer these questions with general purpose libraries you don't even have to write your own code for it.

On the other side, moving away from individual to interoperability between wallets. You can imagine a lot of users in doing interesting things, doing complicated things, who are working with some specific wallet, who's gone through the motions to do all this ad hoc development work to come up with something that matches their policy.

The user might worry "What if I upgrade my software? What if I replaced my hardware device? What if the company that made my wallet goes out of business? What if I want to migrate to [00:13:00] somebody else? Am I really locked in here?" Well, if everybody's doing their own thing and nobody is able to do the analysis they did on their own script for other people's scripts, this is the problem.

It creates this lock in and it creates this risk that it makes users that, makes myself very uncomfortable trying to do some interesting things with Bitcoin. And so miniscript because it's so generic because it's a standard that can cover so many use cases, let's us stop worrying about that.

It means that if your wallet, albeit they're doing something interesting, other wallet doing other interesting things will still be able to work with the addresses you generate and to work with the scripts you generate.

Related to transitioning to new devices is this question of composability. You can imagine a user who, say, is part of the custody solution for some company's bitcoins. Okay, you've got a company that is holding a bunch of coins for whatever reason, and they decide that in order to move any of these coins, they want a quorum of their board of [00:14:00] directors to sign off on, or a quorum of their security officers to sign off or something like that. So, say you have like three of five people need to sign off.

Well, your individual security officers might have their own scripts, or they might have their own policy, right? If I'm a security officer, maybe I don't have it single key, maybe I've got multiple keys that are hidden and various parts of the world. Maybe I have a timelock backup policy or something like that. And ideally, I would like to take this company wide policy, controlling these coins and replace my key in that policy with his larger policy, with a more complicated thing than a single key. And ideally, so would all of my colleagues, so what everybody else is signing off.

But the problem with script then is that you wind up with this massive giant script where different people have inserted different kinds of code. And now you have a problem. How are you going to reason about that? How can you guarantee that the composed is actually secure?

With miniscript we saw we had that tree like structure. You take a key part of the tree, [00:15:00] you remove that, you replace it with a new sub-tree. Problem solved. You don't need to think about interoperability. You don't need to think about composability.

And then finally thinking rather than rather than about composability, fitting yourself into a bigger picture. You can imagine being part of something horizontal where you are one participant in a multisignature or coinjoin or something with other people who are your peers, who are strangers, who are using other wallets, who using different software. How do you work with them? Again, miniscript comes to the rescue.

Right now, there isn't really a good way unless everybody's using exactly the same wallet for them to cooperate to multisign or to do coinjoins. But with miniscripts, they can all understand what each other is doing. They can all be assured that nobody's doing anything funny and they can all work together to produce a complete transaction.

That's all I've got to say. There are implementations of many scripts that are in C++ and in Rust, the C++ one is slated for inclusion in Bitcoin core [00:16:00] this year, maybe knock on, I hope. The Rust one is used in various libraries and the Rust Bitcoin world, as well as in Blockstream's Liquid on our backend.

And then here are the repos that you can go, and you can go to download this code and also a link to Peter Wuille's website, which gives an overview of what miniscript is, how to use it, and has a few online demo tools.

Thanks very much. And, that's all I've got for you. Bye.