Miniscript
This document specifies Miniscript, a language for writing (a subset of) Bitcoin Scripts in a structured way, enabling analysis, composition, generic signing and more.
No reviewsSpecification
Abstract
This document specifies Miniscript, a language for writing (a subset of) Bitcoin Scripts in a structured way, enabling analysis, composition, generic signing and more.
Copyright
This document is licensed under the Creative Commons CC0 1.0 Universal license.
Motivation
Bitcoin Script is an unusual stack-based language with many edge cases, designed for implementing spending conditions consisting of various combinations of signatures, hash locks, and time locks. Yet, despite being limited in functionality, it is still highly nontrivial to:
- Given a combination of spending conditions, finding the most economical script to implement it.
- Given two scripts, construct a script that implements a composition of their spending conditions (e.g. a multisig where one of the "keys" is another multisig).
- Given a script, find out what spending conditions it permits.
- Given a script and access to a sufficient set of private keys, construct a general satisfying witness for it.
- Given a script, be able to predict the cost of spending an output.
- Given a script, know whether particular resource limitations like the ops limit might be hit when spending.
Miniscript functions as a representation for scripts that makes this sort of operations possible. It has a structure that allows composition. It is very easy to statically analyze for various properties (spending conditions, correctness, security properties, malleability, ...). It can be targeted by spending policy compilers. Finally, compatible scripts can easily be converted to Miniscript form - avoiding the need for additional metadata for e.g. signing devices that support it.
Specification
These specifications apply to P2WSH (BIP 141) and Tapscript (BIP 342) scripts, with only minor variations between the two. Differences are noted inline. Unless explicitly stated otherwise, specifications apply to both. P2SH and bare scripts are excluded from this specification.
Translation Table
Miniscript consists of a set of script fragments which are designed to be safely and correctly composable.
This table shows all Miniscript fragments and their associated semantics and Bitcoin Script.
Fragments that do not change the semantics of their subexpressions are called wrappers. Normal
fragments use a fragment(arg1,arg2,...) notation, while wrappers are written using
prefixes separated from other fragments by a colon. The colon is dropped between subsequent
wrappers; e.g. dv:older(144) is the d: wrapper applied to the
v: wrapper applied to the older fragment for 144 blocks.
The pk, pkh, and and_n fragments and t:,
l:, and u: wrappers are syntactic sugar for other Miniscripts, as listed
in the table below. Note that <20> are in hex representation in this document.
Miniscript fragments are expected to be used in BIP 382 wsh() descriptors
and BIP 386 tr() descriptors. Key expressions are specified in
BIP 380. Additionally, BIPs 382 and 386 specify
restrictions on key expressions and what they resolve to - these apply to key expressions in
Miniscript. BIP 382's key expression restrictions apply to Miniscript in P2WSH contexts, and BIP
386's key expression restrictions apply to Miniscript in P2TR contexts. From a user's perspective,
Miniscript is not a separate language, but rather a significant expansion of the descriptor language.
| Semantics | Miniscript Fragment | Bitcoin Script
|----------------------------------------------------------|-------------------------------|---------------
| false | 0 | 0
| true | 1 | 1
| check(key) | pk_k(key) | <key>
| | pk_h(key) | DUP HASH160 <HASH160(key)> EQUALVERIFY
| | pk(key) = c:pk_k(key) | <key> CHECKSIG
| | pkh(key) = c:pk_h(key) | DUP HASH160 <HASH160(key)> EQUALVERIFY CHECKSIG
| nSequence ≥ n (and compatible) | older(n) | <n> CHECKSEQUENCEVERIFY
| nLockTime ≥ n (and compatible) | after(n) | <n> CHECKLOCKTIMEVERIFY
| len(x) = 32 and SHA256(x) = h | sha256(h) | SIZE <0x20> EQUALVERIFY SHA256 <h> EQUAL
| len(x) = 32 and HASH256(x) = h | hash256(h) | SIZE <0x20> EQUALVERIFY HASH256 <h> EQUAL
| len(x) = 32 and RIPEMD160(x) = h | ripemd160(h) | SIZE <0x20> EQUALVERIFY RIPEMD160 <h> EQUAL
| len(x) = 32 and HASH160(x) = h | hash160(h) | SIZE <0x20> EQUALVERIFY HASH160 <h> EQUAL
| (X and Y) or Z | andor(X,Y,Z) | [X] NOTIF [Z] ELSE [Y] ENDIF
| X and Y | and_v(X,Y) | [X] [Y]
| | and_b(X,Y) | [X] [Y] BOOLAND
| | and_n(X,Y) = andor(X,Y,0) | [X] NOTIF 0 ELSE [Y] ENDIF
| X or Z | or_b(X,Z) | [X] [Z] BOOLOR
| | or_c(X,Z) | [X] NOTIF [Z] ENDIF
| | or_d(X,Z) | [X] IFDUP NOTIF [Z] ENDIF
| | or_i(X,Z) | IF [X] ELSE [Z] ENDIF
| X_1 + ... + X_n = k | thresh(k,X_1,...,X_n) | [X_1] [X_2] ADD ... [X_n] ADD ... <k> EQUAL
| check(key_1) + ... + check(key_n) = k (P2WSH only) | multi(k,key_1,...,key_n) | <k> <key_1> ... <key_n> <n> CHECKMULTISIG
| check(key_1) + ... + check(key_n) = k (Tapscript only) | multi_a(k,key_1,...,key_n) | <key_1> CHECKSIG <key_2> CHECKSIGADD ... <key_n> CHECKSIGADD <k> NUMEQUAL
| X (identities) | a:X | TOALTSTACK [X] FROMALTSTACK
| | s:X | SWAP [X]
| | c:X | [X] CHECKSIG
| | t:X = and_v(X,1) | [X] 1
| | d:X | DUP IF [X] ENDIF
| | v:X | [X] VERIFY (or VERIFY version of last opcode in [X])
| | j:X | SIZE 0NOTEQUAL IF [X] ENDIF
| | n:X | [X] 0NOTEQUAL
| | l:X = or_i(0,X) | IF 0 ELSE [X] ENDIF
| | u:X = or_i(X,0) | IF [X] ELSE 0 ENDIF
Type System
Not every Miniscript expression can be composed with every other. Some return their result by putting true or false on the stack; others can only abort or continue. Some require subexpressions that consume an exactly known number of arguments, while others need a subexpression that has a nonzero top stack element to satisfy. To model all these properties, we define a correctness type system for Miniscript.
Correctness
Every miniscript expression has one of four basic types: "B" (base), "V" (verify), "K" (key) and "W" (wrapped). Then there are 5 type modifiers that guarantee additional properties: "z" (zero-arg), "o" (one-arg), "n" (nonzero), "d" (dissatisfiable), and "u" (unit).
The following table lists the correctness requirements for each of the Miniscript expressions, and its type properties in function of those of their subexpressions.
| Miniscript | Requires | Type | Properties
|------------------------------|-------------------------------------------------------|-------------|-----------
| 0 | | B | z; u; d
| 1 | | B | z; u
| pk_k(key) | | K | o; n; d; u
| pk_h(key) | | K | n; d; u
| older(n), after(n) | 1 ≤ n < 2<sup>31</sup> | B | z
| sha256(h) | | B | o; n; d; u
| ripemd160(h) | | B | o; n; d; u
| hash256(h) | | B | o; n; d; u
| hash160(h) | | B | o; n; d; u
| andor(X,Y,Z) | X is Bdu; Y and Z are both B, K, or V | same as Y/Z | z=z<sub>X</sub>z<sub>Y</sub>z<sub>Z</sub>; o=z<sub>X</sub>o<sub>Y</sub>o<sub>Z</sub> or o<sub>X</sub>z<sub>Y</sub>z<sub>Z</sub>; u=u<sub>Y</sub>u<sub>Z</sub>; d=d<sub>Z</sub>
| and_v(X,Y) | X is V; Y is B, K, or V | same as Y | z=z<sub>X</sub>z<sub>Y</sub>; o=z<sub>X</sub>o<sub>Y</sub> or z<sub>Y</sub>o<sub>X</sub>; n=n<sub>X</sub> or z<sub>X</sub>n<sub>Y</sub>; u=u<sub>Y</sub>
| and_b(X,Y) | X is B; Y is W | B | z=z<sub>X</sub>z<sub>Y</sub>; o=z<sub>X</sub>o<sub>Y</sub> or z<sub>Y</sub>o<sub>X</sub>; n=n<sub>X</sub> or z<sub>X</sub>n<sub>Y</sub>; d=d<sub>X</sub>d<sub>Y</sub>; u
| or_b(X,Z) | X is Bd; Z is Wd | B | z=z<sub>X</sub>z<sub>Z</sub>; o=z<sub>X</sub>o<sub>Z</sub> or z<sub>Z</sub>o<sub>X</sub>; d; u
| or_c(X,Z) | X is Bdu; Z is V | V | z=z<sub>X</sub>z<sub>Z</sub>; o=o<sub>X</sub>z<sub>Z</sub>
| or_d(X,Z) | X is Bdu; Z is B | B | z=z<sub>X</sub>z<sub>Z</sub>; o=o<sub>X</sub>z<sub>Z</sub>; d=d<sub>Z</sub>; u=u<sub>Z</sub>
| or_i(X,Z) | both are B, K, or V | same as X/Z | o=z<sub>X</sub>z<sub>Z</sub>; u=u<sub>X</sub>u<sub>Z</sub>; d=d<sub>X</sub> or d<sub>Z</sub>
| thresh(k,X_1,...,X_n) | 1 ≤ k ≤ n; X<sub>1</sub> is Bdu; others are Wdu | B | z=all are z; o=all are z except one is o; d; u
| multi(k,key_1,...,key_n) | 1 ≤ k ≤ n ≤ 20 | B | n; d; u
| multi_a(k,key_1,...,key_n) | 1 ≤ k ≤ n | B | d; u
| a:X | X is B | W | d=d<sub>X</sub>; u=u<sub>X</sub>
| s:X | X is Bo | W | d=d<sub>X</sub>; u=u<sub>X</sub>
| c:X | X is K | B | o=o<sub>X</sub>; n=n<sub>X</sub>; d=d<sub>X</sub>; u
| d:X | X is Vz | B | o; n; d; (Tapscript only) u
| v:X | X is B | V | z=z<sub>X</sub>; o=o<sub>X</sub>; n=n<sub>X</sub>
| j:X | X is Bn | B | o=o<sub>X</sub>; n; d; u=u<sub>X</sub>
| n:X | X is B | B | z=z<sub>X</sub>; o=o<sub>X</sub>; n=n<sub>X</sub>; d=d<sub>X</sub>; u
Timelock Type Mixing
There is one additional correctness property that Miniscript expressions must satisfy: the four timelock types (absolute time based, absolute height based, relative time based, and relative height based) must not be mixed in an incompatible way.
Within and combinators and the thresh combinator where k >= 2, it is illegal for both absolute
height based and time based timelocks to appear, or for both relative height based and time based
timelocks to appear.
For all other combinators, it is legal to mix timelock types. It is also always legal to mix absolute and relative timelocks (even if one is height based and the other is time based).
Malleability
Malleability is the ability for a third party (someone who does not hold a participating private key) to modify an existing satisfaction into another valid satisfaction. To analyze the malleability guarantees of a script we define three additional type properties: "s" (signed), "f" (forced) and "e" (expressive).
The following table lists the malleability properties and requirement of each fragment.
| Miniscript | Requires | Properties
|------------------------------|---------------------------------------------------------------------|-----------
| 0 | | s, e
| 1 | | f
| pk_k(key) | | s, e
| pk_h(key) | | s, e
| older(n) | | f
| after(n) | | f
| sha256(h) | |
| ripemd160(h) |
[Content truncated — view full spec at source]
Discussion (0 threads)
Loading discussions...