Miniscript 101: A Technical Guide

This article is machine translated
Show original

Author: Nunchuk

Source: https://nunchuk.io/blog/miniscript101

1. Introduction

What is "Miniscript"?

The Bitcoin protocol has always included a powerful programming language (Bitcoin Script) that allows for locking funds beyond a single correct signature. Using Bitcoin Script, you can combine multiple public keys, time locks, hash preimages, and complex logic branches. However, in reality, Bitcoin Script is rarely used directly because it is difficult to write correct code, errors can permanently lock funds, and the resulting code is nearly impossible to directly analyze.

Miniscript ( BIP-379 ) is a "structured language for writing Bitcoin Script code, offering analysis, composition, and universal signature capabilities," proposed by Pieter Wuille and his collaborators. It addresses the usability and security issues of bare Bitcoin Script while maintaining full compatibility with current Bitcoin rules.

At its core, Miniscript is like a Lego box of Bitcoin spending rules. Each block represents a small, precisely defined condition, such as a public key that must sign, a time period that must elapse, or a secret value that must be revealed. One block can be swapped out for another, allowing for flexible and alternative spending paths. By combining blocks using logical operators like AND, OR, and thresholds, you can develop spending conditions as simple or complex as you need. Crucially, Miniscript policies are analyzable: wallets can check in advance who can spend and under what conditions, reducing the risk of funds being locked up by invalid scripts.

This structured approach allows us to safely express spending conditions like the following:

  • Requires signatures from at least 2 of the 3 directors - unless the funds have not been moved for 6 consecutive months, then only 1 signature is required to move the funds.
  • Alice and Bob must be together to spend the funds, or Charlie can move the funds alone after they have sat dormant for 1 year.
  • Either reveal the original image of a hash value, or wait until the block height is 100 0000 (to spend).

What's the point of it?

Using Miniscript, spending conditions can go beyond single-sig and simple multi-sig. You can define rules like this:

  • "A and B together can spend the funds at any time; alternatively, C alone can spend the funds after they have been idle for 1 year";
  • “Now it requires two of the three public keys to sign together; after the funds have been dormant for six months, it will only require one of the three public keys to sign together.”

These flexible conditions cater to practical use cases such as estate planning, tiered corporate finances, and emergency recovery; they make advanced security accessible to ordinary Bitcoin users. Importantly, all Miniscript conditions are enforced directly on the Bitcoin blockchain, requiring no additional trust assumptions beyond the Bitcoin network itself .

2. Core Concepts of Miniscript

Now, let's look at the core modules of Miniscript. Each element (a Miniscript snippet) represents a specific spending condition, and when combined together, they can create flexible and secure spending strategies.

2.1 Public Key

Public key: pk(k)

This is the simplest condition in Miniscript, requiring a signature from a specific public key. It represents the basic "single-signature" spending condition and is also used as the basis for more advanced spending conditions.

  • Example : Requiring a signature to spend funds
  • Miniscript : pk(Alice)

miniscript-fragment-public-key.png

- Miniscript snippet: Public key -

2.2 Multi-Signature

Multi-signature: multi(k, …)

Traditional multi-signature spending conditions require k out of n public keys to provide signatures. Its child elements can only be public keys.

  • Example : Requires signatures from 2 out of 3 public keys to spend.
  • Miniscript : multi(2, Alice, Bob, Charlie)

miniscript-fragment-multisig.png

- Miniscript snippet: Multi-signature -

2.3 Time Lock

A timelock prevents locked bitcoins from being spent before a certain point in time. It is a native feature of Bitcoin Script and one of the most useful Miniscript modules.

Time locks enforce rules like "funds can only be moved after six months" and "this public key can only be used 30 days after the funds were deposited." Nodes in the Bitcoin network will reject transactions that attempt to spend these funds before this time. Once this time point has passed, the funds can be spent normally, and the enabled spending path cannot be locked back.

Bitcoin Script has two types of time locks: absolute time locks and relative time locks.

Absolute time lock: after(n)

Funds are locked until the network reaches a certain block height or time. Once the blockchain grows beyond that height, the spending conditions with this time lock are activated and permanently available.

  • Example : Spend with a signature after the blockchain reaches UNIX timestamp 17 5000 0000 (approximately June 2025).
  • Miniscript : and_v(v:pk(Alice),after(1750000000))

An absolute time lock sets a fixed future time; after an absolute time lock expires, setting an absolute time lock with the same conditions will no longer have a binding effect.

miniscript-fragment-absolute-timelock.png

- Miniscript snippet: Absolute time lock -

Relative time lock: older(n)

Locks funds for a period of time until it passes. This period can be defined in blocks or calendar time (date, hour). A relative timelock counts down from the moment the associated UTXO is created; once the defined period has passed, the associated spend path becomes active.

  • Example : After 12960 blocks (approximately 90 days) of the funds being mined, a signature is required to spend them.
  • Miniscript : and_v(v:pk(Alice),older(12960)

The relative timelocks of each UTXO are independent of each other and are not synchronized just because they are all in the same wallet. After a UTXO's relative timelock expires, the countdown can be "refreshed" using the same timelock conditions - it can be transferred to a new address in the same wallet to reset the timelock.

miniscript-fragment-relative-timelock.png

- Miniscript snippet: relative time locks -

- - -

When setting a timelock, the calendar date displayed in the wallet software interface is only an estimate. If the timelock is set based on a block height, the timelock will expire when the network reaches that height. If the timelock is set based on calendar time, the Bitcoin network uses the median of past block times (specifically, the median of the timestamps of the past 11 blocks) to determine the current time, which may deviate from the calendar and clock used by humans. Therefore, the time at which a spending transaction becomes valid depends on the state of the Bitcoin network and may not exactly match the expected time (displayed in the interface).

2.4 Hash Lock

A hash lock requires the discovery of a secret value (its preimage) corresponding to a hash value. Unless the secret is revealed, the lock will not be unlocked.

  • Example : The original image behind a SHA256 hash value H must be revealed and a signature must be provided before it can be spent.
  • Miniscript : and_v(v:pk(Alice),sha256(H))

Hash lock types in Miniscript

  • sha256(H) - the preimage must be SHA256ed to produce H (the preimage is expected to be a 64-bit hexadecimal string)
  • hash256(H) — the preimage must be H after two consecutive SHA256 operations (the preimage is expected to be a 64-bit hexadecimal string)
  • ripemd160(H) – the preimage must result in H after the RIPEMD-160 operation (the preimage is expected to be a 40-digit hexadecimal string)
  • hash160(H) - also must be HASH160 (running SHA256 first, then running RIPEMD160) to get H (the expected preimage is a 40-digit hexadecimal string)

miniscript-fragment-hashlock.png

- Miniscript snippet: Hash lock -

2.5 Logical Basics: AND, OR, ANDOR

These three logical operators are the foundation of Miniscript. They describe how different conditions can be combined (usually via timelocks).

AND : To unlock, both conditions must be true.

  • Example : Spending requires Alice's signature, and must be done 12960 blocks (about 90 days) after receiving the funds.
  • Miniscript : and_v(v:pk(Alice),older(12960))

miniscript-fragment-and.png

- Miniscript snippet: AND -

- - -

OR : If at least one of the two conditions is true, the item will be unlocked.

  • Example : Spending requires a signature from either of two public keys.
  • Miniscript : or_d(pk(Alice),pk(Bob))

miniscript-fragment-or.png

- Miniscript snippet: OR -

ANDOR : Funds are locked using an if/else rule: if the first condition is true, then the second condition must also be true (to unlock); if the first condition is false, then the third condition must be true (to spend).

  • Example : If Alice signs, then Bob also needs to sign; if Alice does not sign, then Charlie's signature is required.
  • Miniscript : andor(pk(Alice), pk(Bob), pk(Charlie))

miniscript-fragment-and-or.png

- Miniscript snippet: ANDOR -

2.6 Threshold

Threshold: thresh(k, …)

Threshold conditions are more flexible than multi-signatures. They require k conditions to be true; however, unlike multi-signatures, their sub-elements are not limited to public keys and can be logical expressions, time locks, hash locks, and so on.

  • Example : Alice and Bob sign together (to spend); after the funds sit dormant for 90 days, either person can spend them individually.
  • Miniscript : thresh(2,pk(Alice),s:pk(Bob),sln:older(12960))

miniscript-fragment-threshold.png

- Miniscript snippet: Threshold -

2.7 Taproot Scripts

Taproot allows you to commit multiple spending branches for your funds, and only need to reveal one (the one you actually use) when you spend it. It provides two spending methods:

  • Key path : Spending with an aggregate public key. This transaction appears on the blockchain as a regular single-signature transaction, even if the public key is constructed by multiple parties (e.g. using MuSig2).
  • Script path : Use one of the Taproot script branches that were committed. Only the branch you use will be revealed, the rest will be hidden.

This structure balances efficiency and privacy: daily use can be done through the key path; while more complex spending conditions can be hidden until they are needed.

  • Example : Daily spending uses an aggregate public key (called Alice) in the key path; if the aggregate public key cannot sign, the script path allows Charlie to spend at any time with a signature, while Bob cannot spend until 90 days after the funds are created.
  • Miniscript : tr(pk(Alice), {and_v(v:pk(Bob),older(12960)),pk(Charlie)})

miniscript-fragment-taproot-scripts.png

- Miniscript snippets: Taproot scripts -

2.8 MuSig2

MuSig2 is a Schnorr-based multi-signature scheme that allows multiple participants to jointly generate an aggregate signature. On-chain, this aggregate signature appears indistinguishable from a regular single signature. This improves privacy and efficiency while reducing transaction size and fees.

  • For example , spending requires the signatures of two of Alice, Bob, and Charlie. The signatures they generate appear as a single signature on the blockchain, making it impossible to tell it's a multi-party wallet. This makes multi-party wallets more private and efficient.
  • Miniscript : tr(musig(Alice, Charlie), {pk(musig(Alice, Bob)),pk(musig(Bob, Charlie))})

miniscript-fragment-musig2.png

- Miniscript snippet: MuSig2 -

3. Using Miniscript in Nunchuk

3.1 Creating a Miniscript Wallet

Nunchuk makes it easy to build advanced spending conditions using Miniscript. You can start with a ready-made template or enter your own custom script.

Create a miniscript wallet in Nunchuk: Home → Create new wallet → Miniscript

  • Template : Choose a spending condition, such as "Expanding Multisig," "Decaying Multisig," or "Flexible Multisig." Each template lets you adjust parameters like the number of public keys and time delays, without writing any code.

create-miniscript-wallet-via-timelock.png

- Create a miniscript wallet from a template -

  • Custom Scripts : For advanced users, you can paste a plaintext Miniscript spending condition, or import it from a file. Nunchuk will automatically parse the script, check for correctness, and display the spending condition in plain English.

create-miniscript-wallet-using-a-custom-script.png

- Create a miniscript wallet using custom scripts -

3.2 Miniscript Group Wallet

Nunchuk's "Group Wallet" feature allows multiple people using multiple devices to jointly manage a Bitcoin wallet, with end-to-end encrypted data communications. Each participant maintains their own keys, and spending conditions are collectively enforced, independent of any custodian. When combined with Miniscript, Group Wallet supports advanced multi-party conditions that mirror real-world governance mechanisms. Like standard Miniscript wallets, you can start with ready-made templates or create your own custom scripts.

To create a miniscript group wallet in Nunchuk, click: Home → Create new wallet → Group wallet → Settings → Miniscript.

minisciprt-group-wallet.png

Example: A company's two executives and four directors create a group wallet. Daily operations only require signatures from the two executives; however, in another spending path, any three of the four directors can authorize a transaction.

3.3 Miniscript Wallet Recovery

To restore a miniscript wallet, in addition to common materials such as private keys and preimages, a backed-up wallet configuration file (either in the form of an output descriptor or a BSMS file) is absolutely necessary.

The BSMS format is an encapsulation of an Output Descriptor, which contains metadata such as the wallet's first address. This metadata acts as a checksum and allows for quick wallet location. The wallet configuration file acts as a map, defining how a wallet is constructed.

The same requirement applies to Miniscript group wallets: without the wallet configuration file, the wallet cannot be reconstructed, even if all members' private keys are present.

To restore a miniscript wallet in Nunchuk, click:

Home → Create new wallet → Recover existing wallet → Recover using BSMS/descriptors

To restore a miniscript group wallet in Nunchuk, click:

Home → Create new wallet → Recover existing wallet → Recover group wallet

miniscript-wallet-recovery.png

- Restore a miniscript wallet or miniscript group wallet -

 BSMS 1.0tr(xpub661MyMwAqRbcGgLWCDJNFcLYg8KgQimdffZdRobPJ585b93QjtCgqbPCo54DP3kpzwFpaZxoi6Snia3VDSV4oV81H4BxfaUbAzP2EpGHWDr/**,{multi_a(2,[8a0ba421/87'/0'/0']xpub6DWv19xigzHyBJJvE4iMTyTxQrn5TkBAr8k4gUJ8gycB8U7S7s8QRfBTa4Je2on9FE7jiUa3ijxuNyygEcpe8CGQUEz6W2PGtZ8SUJWc8fC/**,[d33f8331/87'/0'/0']xpub6C3RqV6jatGDLEiGpi92fsDLApCLC6SB28bMjwSaU4w3sdxmhWJRmzsxPDr8zv2hkyt1czkd3siMHJ6uAzN4T1gC5W6Vdd75XyJknN9N1Zb/**,[45c72f63/87'/0'/0']xpub6Ci35gULWq49uY6txiEHLJd8R9ESbadyed8zPACMgi6Cu5cd4BLG9p1ZDP3PnGNNaEHbGuy1uzEJDsEdWQck1C75DkaB13P8kX8UZkc7E8i/**),and_v(v:multi_a(1,[1e897bbf/87'/0'/0']xpub6CSCZZo8sDS2wjXUitr4FQUZwenEL1KcZrgYvi2mvSnVbYztYBxVLj5mKYcpNvB6RkLNEQzaaf8SWquzdhC6ncwasXk8STEjKwYRrd1QZcZ/**,[0cd15c3e/87'/0'/0']xpub6C3JCSGe5J2iqZymN7pKrYisD9po9FRqSRNot6561iLrzFjrPMNm8qn5VeYgTdWAtR66Kfr9oZWrjxSDLxB7GQ5dEi7hiUbjHyDxjaQxww6/**,[03c341e8/87'/0'/0']xpub6Bw2SYRUCc3Pcsgk39WkvkewHnxSLSERZmkUPBy91nrzKXehFBNLEzF2uJ2YiBhrS7kqagpGxBqhVziYawzUHePkB7pQGBMAnQmoYAxEAwz/**),after(1758819600))})/0/*,/1/*bc1pzmlufvqn5dpcquqysj4fr9skwxjj60wg7zyrpk4j8ftccz9ck9rs9fmjam

- A BSMS file for a miniscript wallet -

4. Application Scenarios and Case Studies

4.1 Application Scenarios

Miniscript opens the door to spending strategies beyond basic multi-signature. Some real-world applications include:

  • Estate Planning : A safe that heirs can unlock after a defined delay, while giving the wallet owner full control over the funds during their lifetime.
  • Corporate treasury : Requiring signatures from multiple executives to disburse funds from the treasury while concealing backup spending paths for emergencies.
  • Custody and Exchange : Use hash locks and time locks to spend atomic swaps and secure custody without intermediaries.
  • Insurance : Insurance providers can enforce payout conditions (requiring multiple signatures), or funds can be released after a timelock expires and a verifiable statement of events is provided.
  • Lending : Loans can be secured by Bitcoin collateral; Bitcoin collateral can enforce repayment or liquidation through threshold conditions, time locks, and refund paths, reducing the need for trusted intermediaries.
  • Emergency Recovery : A wallet that normally requires a 2-of-3 multi-signature to unlock can, after a long period of inactivity, activate an emergency recovery spend condition where a recovery key or set of recovery keys can unlock the funds.
  • Privacy-preserving custody : Using Taproot and MuSig2, even complex multi-party spending transactions appear on-chain as single-signature transactions, preserving privacy while maintaining robust security.

4.2 Case

A) Inheritance with time lock (once-and-for-all recovery)

  • The idea behind spending conditions : Currently using 2-of-3 multi-signature; after you are offline for 6 months, a designated fallback key can withdraw funds from the wallet.

  • Why it matters : Reduces the risk of permanent loss of funds while not giving direct control to others.

  • How it works : Threshold signatures and a recovery path with time locks.

  • Miniscript example :

     andor( pk(backup_key), older(4224679), multi(2,A,B,C) )

B) Corporate Treasury with Tiered Licensing

  • The idea behind spending conditions :

    • Daily expenses: Any 2 financial directors + 1 joint signing machine (such as hardware signing module (HSM)/KMS (key management server))
    • Large expenditure: Any 2 financial directors + chief financial officer (CFO)
    • Delay/Emergency Visit: Any 2 Finance Directors can spend
  • What it's about : Everyday convenience and security.

  • How it works : Threshold/AND with OR branching and an optional time lock. Teams choose the branch they want to use.

  • Miniscript example :

     and_v( or_c( pk(HSM), or_i( v:pk(CFO), v:older(4195485) ) ), multi(2,LeadA,LeadB,LeadC))

C) Controllable custody for OTC transactions

  • The idea behind spending conditions : Buyer + Seller, or, after the time window ends, either party + arbitrator

  • Why it matters : No custodian. Clear, rules-based mediation path.

  • How it works : OR logic with a time-lock fallback condition.

  • Miniscript example :

     thresh(2, pk(Buyer), s:pk(Seller), sj:and_v( v:pk(Arbiter), n:older(4194472) ) )

D) Multiple wallets that are difficult to trace on the chain

  • The idea behind spending conditions : three devices have joint control; a single aggregate public key can be used to spend, so the number of signers is not exposed.

  • Why it matters : Achieve team security without exposing your governance structure.

  • How it works : You can choose between Taproot and MuSig2. MuSig2 aggregates multiple signers into a single public key; Taproot hides unused branches. Within a script path, only the executed branches are revealed.

  • Miniscript example (Taproot) :

     tr( musig(A,B), { pk(musig(A,C)), pk(musig(B,C)) } ) 

5. Conclusion

Bitcoin has always had the ability to use rich spending conditions, but its low-level programming language was too difficult and dangerous for most users. Miniscript changes this by providing a structured, safe, and composable language for expressing spending conditions.

With Miniscript, advanced uses such as estate planning, corporate treasury, atomic swaps, privacy-preserving custody, and more are all within reach.

As a software wallet, Nunchuk brings Miniscript to a user-friendly interface, giving the Bitcoin ecosystem a powerful new standard. Finally, complex contracts can be expressed in a secure, analyzable, and readable way—unlocking the next generation of Bitcoin custody and smart contract design.

Footnote: Hardware Signature Devices Supporting MiniScript

(Last updated on August 27, 2025)

  • Support for pure SegWit Miniscript : Tapsigner, Coldcard (EDGE firmware v6.3.3 and later), Jade (firmware v1.0.30 and later), Jade Plus (firmware v1.0.30 and later), Ledger (firmware v2.1.0 and later), Spectre DIY (firmware v1.5.0 and later)
  • Taproot Miniscript support: Coldcard (EDGE firmware v6.3.3 and later), Ledger (firmware v2.2.1 and later), Spectre DIY (firmware v1.9.0 and later)
  • MuSig2 support: Not yet (i.e. only software keys can be used currently)

(over)

Source
Disclaimer: The content above is only the author's opinion which does not represent any position of Followin, and is not intended as, and shall not be understood or construed as, investment advice from Followin.
Like
Add to Favorites
Comments