MiniTapscript: port Miniscript to Tapscript (
descriptors) Apr 5, 2023
The PR branch HEAD was 6e3b37b at the time of this review club meeting.
Background and prior work
Miniscript is a language for writing (a subset of) Bitcoin Scripts in a structured way, enabling analysis, composition, generic signing and more. Miniscript support in Bitcoin Core has been an ongoing effort, with watch-only support for Miniscript in P2WSH descriptors added in
v24.0.1 and signing support to be added in the upcoming
v25. For background:
https://bitcoin.sipa.be/miniscript gives an overview of the Miniscript language
#24147 provides the rationale and initial backbone needed for Miniscript support in Bitcoin Core
#24148 adds watch-only support for Miniscript descriptors (see previous review club #24148)
#24149 adds signing support for Miniscript descriptors TapMiniscript
shares most operations with legacy Bitcoin Script, there are a few Tapscript notable differences. As such, TapMiniscript has been a project to support Tapscript in Miniscript. For background:
This gist contains the initial design and discussion on supporting Miniscript in Tapscript
#134 adds Tapscript support in Miniscript Putting it all together
Putting it all together, this PR adds support for Tapscript in Miniscript in Bitcoin Core and makes Miniscript available inside
tr() descriptors, both with watching and signing support.
Did you review the PR?
Concept ACK, approach ACK, tested ACK, or NACK? What was your review approach?
In your own words, what are some of the differences between Segwit v0 Script (Bitcoin Script with the Segwit Soft Fork rules) and Tapscript rules that may be relevant to Miniscript? Why?
What is Tapscript?
multi_a fragment for Tapscript. How is this different than the existing
multi fragment? Does it have the same properties as
In Miniscript, we have type modifiers, which guarantee additional properties for an expression.
866284d makes the wrapper “ d:” have the “ u” property under Tapscript.
What is the “
d:” wrapper and the “ u” type modifier? Why is it that we can make
d: have the u property here? Why not in non-Tapscript Miniscript? This PR adds some logic for statically ensuring no spending path exceeds the stack size at execution time:
Why does this matter for Tapscript?
What’s the approach taken by this PR? What are the pros/cons? (hint:
efdd154) Can you think of an alternative approach to ensure no spending path exceeds the stack size?
e81635c, the scripts are optionally padded during fuzzing. Why? What is the most significant change to the descriptor logic in this PR (hint:
08db38a). Why is it needed? Meeting Log
1 17:00 <josie> #startmeeting
7 17:00 <effexzi> Hi every1
8 17:01 <josie> any first timers for the PR review club?
10 17:01 <turkycat> yep, first timer here
11 17:01 <Alex66> hi, yap first time
12 17:02 <josie> turkycat, Alex66: welcome!
14 17:05 <josie> just as a quick reminder: no need to ask about asking a question. if you have a question, jump in!
15 17:05 <josie> first question: did you get a chance to review the PR? give a y for yes or an n for no
20 17:06 <josie> if you did get a chance to review the PR, what did was your approach? did you ACK/NACK?
21 17:06 <stickies-v> n, mostly looked at the notes/questions
22 17:07 <kevkevin> I just visually read the code and got to understand miniscript.cpp and miniscript.h concept ACK
24 17:07 <abubakar> I am running the test currently concept ACK
25 17:07 <josie> (or even if you didn't fully review, what do you think regarding the concept and the approach)
26 17:08 <LarryRuane> yes concept ACK also from me but this is an area I'm not familiar with at all
27 17:09 <stickies-v> taproot enables much more complex scripting, so big concept ack for adding miniscript compatibility
28 17:09 <brunoerg> concept ACK
29 17:10 <turkycat> I'm comfortable with the code changes and understand them- descriptors in general though not so much. some of the concepts of the descriptors are still fuzzy to me after reading the doc on them. hoping to pick up more today
30 17:11 <LarryRuane> I have a very basic question (sorry), but this https://bitcoin.sipa.be/miniscript/ already mentions Tapscript, so what is this PR for? I'm unclear on what is already done and what more is needed
31 17:11 <josie> cool! for the next question, I think it makes more sense to start with 3: what is tapscript?
32 17:11 <josie> turkycat: descriptors are a really big topic!
34 17:12 <abubakar> tapscript is a modified version of bitcoin script which removes and adds some opcodes like checksigadd
35 17:12 <LarryRuane> stickies-v: thanks
36 17:13 <stickies-v> bitcoin core currently is not yet able to parse tapscript miniscript, so the website is just describing the spec already
37 17:13 <brunoerg> tapscript is a scripting language used in Bitcoin which can use Schnorr Signatures and other things
38 17:13 <kevkevin> tapscript is a scripting language that utilizes the upgrades from the taproot update
39 17:14 <josie> abubakar: correct!
40 17:14 <LarryRuane> The interactive aspect of that website is really cool and amazing
41 17:15 <abubakar> only v1 scrippubkeys can use tapscript i think
42 17:16 <josie> yep, more specifically, tapscript is built of segwit v0 script
43 17:16 <turkycat> abubakar v1 as in segwit v1 (taproot) as apposed to segwit v0?
44 17:16 <josie> s/built of/built on/
45 17:17 <josie> turkeycat: yep! more importantly, segwit v1 introduced the concept of a leaf version. tapscript is defined as leaf version 0
46 17:18 <abubakar> turkycat: yes segwit v0 uses the bitcoin script
47 17:18 <josie> a few of you have already mentioned some differences, but can you summarize in your own words some differences between Segwit v0 Script and Tapscript?
48 17:18 <turkycat> yep just needed to clarify that there aren't two versions of something else in context
49 17:19 <LarryRuane> ah so there can later be leaf versions 1, 2, ..., all within segwit v1
50 17:19 <josie> LarryRuane: the miniscript website is awesome! I reference it constantly
51 17:20 <turkycat> segwit v0 supports pubkeyhash and script hash operations via witness data. taproot allows for a merkle tree of different script leaves that can be revealed at spending time or satisfied with a composite signature of a single key
52 17:20 <josie> LarryRuane: that's right! in fact, you could create a TapTree where each leaf has it's own leaf version
53 17:21 <brunoerg> turkycat: MAST, right?
54 17:21 <stickies-v> josie: OP_(NOT)IF is now only allowed (consensus) to have 0 or 1 as its argument, whereas in v0 e.g. 4 would also evaluate as true (this is also referred to as MINIMALIF)
55 17:21 <abubakar> multisig is now different in tapscript because of the new checksigadd opcode
56 17:22 <josie> turkycat: close. I'd say it's more correct to say that segwit v1 introduces the merkle tree of scripts (with leaf versions) and tapscript is defined as leaf version 0
57 17:22 <turkycat> brunoerg - I had to google "MAST", but I think so. All I know is that with a single merkle root you can have an unbalanced trie of script leaves
58 17:23 <josie> stickies-v: yep, this is an important one! previously minimalif was only a policy rule, whereas in tapscript it is now a consensus rule
59 17:23 <turkycat> josie ACK. re-read your question and realized I didn't parse correctly on the first go
61 17:24 <josie> abubakar: yep, tapscript adds a new op_code checksigadd. what about the old multisig opcodes from legacy and segwit v0?
62 17:24 <kevkevin> isnt the old multisig op code CHECKMULTISIG?
63 17:25 <abubakar> its removed i think, i might be wrong on this
64 17:25 <josie> kevkevin: yep! CHECKMULTISIG (and CHECKMULTISIGVERIFY)
65 17:25 <stickies-v> kevkevin: yes, OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY were used up until segwit v0 - what's the question?
66 17:26 <abubakar> kevkevin: yes
67 17:26 <stickies-v> oh I see, you were just listing them. sorry
68 17:26 <josie> abubakar: you are correct, CHECKMULTISIG and CHECKMULTISIGVERIFY are removed from tapscript
69 17:28 <josie> what about limits in segwit v0 vs tapscript? any changes here?
70 17:28 <stickies-v> mmm I don't think they're removed? just made to behave like OP_RETURN, pretty much?
71 17:28 <stickies-v> as in - they fail script termination
72 17:28 <stickies-v> *script execution
73 17:29 <abubakar> stickies-v: +1
74 17:29 <abubakar> josie: thanks
75 17:29 <josie> stickies-v: that's a great point, actually! you are correct: they now behave like OP_RETURN
76 17:30 <josie> so instead of saying removed, the more correct terminology would be "disabled"
77 17:31 <brunoerg> Sorry couldn't get it, what do you mean by "disabled"?
78 17:31 <turkycat> extending Script requires the redefining of the numbered NO_OP codes (like NO_OP1), where I could make a WAG that tapscript can be extensible without requiring to always be backwards compatible? by adding a new version I mean
79 17:33 <turkycat> segwit v0 still relies on 'legacy' Script, so now we could theoretically create all sorts of new capabilities with new versions?
80 17:33 <stickies-v> brunoerg: if during script execution one of those opcodes is encountered, script termination fails. if the opcodes are in a branch that's not executed, they're ignored
81 17:33 <brunoerg> ok, I think I got it, disabled means they are still present in the language but they're no longer executable
82 17:34 <brunoerg> stickies-v: cool, thanks
83 17:34 <stickies-v> (i don't know why i keep saying script termination instead of script execution, sorry)
84 17:35 <josie> brunoerg, stickies-v: that's my understanding as well. I'm not sure about this, but perhaps it also means those OP_CODE numbers are still reserved? meaning they cant be redefined to mean something else in the future
85 17:36 <brunoerg> yes, I think they're still reserved to keep backwards compatible
86 17:37 <josie> turkycat: actually, one of the key features of tapscript is that it allows adding new op_codes using OP_SUCCESS, instead of NO_OP
87 17:37 <brunoerg> so older scripts can still be decoded correctly
88 17:37 <abubakar> josie: is it limit to the size of the items in stack during execution of the script
89 17:38 <turkycat> @josie cool, added
90 17:38 <turkycat> tapscript walkthrough to reading list
91 17:39 <josie> abubakar: the stack element size, and the element count limit are the same, but the non-push opcodes limit of 201 per script was removed and the maximum script size limit of 10,000 bytes was removed
92 17:40 <josie> okay, moving on to question 4: the PR adds a `multi_a` fragment for Tapscript. how is this different than the existing `multi` fragment?
93 17:41 <josie> does `multi_a` have the same properties as `multi`? why/why not?
94 17:41 <kevkevin> is the difference multi_a uses checksigadd while multi uses checkmultisig
95 17:41 <kevkevin> they have the same properties tho?
96 17:42 <stickies-v> `multi` always consumes at least one stack element (because of the off-by-one bug, i think?), `multi_a` does not
97 17:43 <kevkevin> ooh ok didn't know that bit of info
98 17:44 <abubakar> kevkevin: +1 multi output has the checkmultisig opcode which was removed, the fragment output script differs
99 17:45 <josie> kevkevin, abubakar: tapscript definitely uses checksigadd, but I suppose we could have reused the same multi fragment and recognized that it was being used in a tapscript context. but this would only be possible if the multi fragment had the same properties under both p2wsh and tapscript
100 17:46 <kevkevin> ohh is it because the tapscript inputs are 32 bytes and p2wsh 33 not too sure on this one
101 17:47 <josie> stickies-v: multi does have the n property, which means it must always consume at least one stack element. good point about the off-by-one tho, I'm not sure if this is the reason
102 17:49 <josie> let me rephrase the question a bit: the `multi` fragment has the `n` type modifier, which means it must always consume at least one stack element. `multi_a` does not have the `n` type modifier, which means the top of the stack can be the empty vector. any ideas as to why?
103 17:51 <stickies-v> if we pass `0` as the first argument to `multi_a` it would be a 0-0 multisig, so nothing gets popped off the stack?
104 17:51 <abubakar> because of the 0 prefix
105 17:53 <josie> stickies-v: instead of a 0-0, think about how CHECKSIGADD would be used for a 2-3 multisig. how many parameters does CSA expect?
106 17:53 <turkycat> maybe because it still requires n items to satisfy the NUMEQUAL at the end, but if we're using, say 2-of-3 multisig then we only need 2 valid signatures? idk feels like a shaky guess but there doesn't appear to be a 'k' value on `multi_a`
107 17:54 <turkycat> oops, yes there is- at the end before NUMEQUAL
108 17:54 <josie> turkycat: bingo! CSA expects N sigs, but only k are needed for the NUMEQUAL. so n - k of the sigs will be the empty vector
109 17:55 <turkycat> score 1 for the WAGs
110 17:56 <josie> CHECKMULTISIG had you pass both k and n, so it would be expecting exactly k sigs, non of which were empty
111 17:57 <josie> we are pretty close to time, so instead of going into the next Q (which is a pretty big one), are there any questions about stuff we've talked about so far?
112 17:57 <josie> also, any interest in finishing the remaining questions in a follow-up review club? there's some pretty good stuff in the remaining questions :)
113 17:58 <LarryRuane> I would say yes to follow-up, and I'll try to be better prepared!
114 17:58 <kevkevin> yup I'd say yes to a follow up aswell
115 17:59 <josie> cool, follow-up it is! probably should have started with less questions because this is a really big topic! what we are seeing in this PR is the tip of the iceberg
116 17:59 <brunoerg> yea, a follow-up would be great
117 17:59 <abubakar> +1 would like a part 2 :)
118 18:00 <turkycat> yea, I'll be able to read the new items on my list before then
119 18:00 <stickies-v> josie: contrary to OP_CHECKMULTISIG(VERIFY), CSA always operates on a single signature
120 18:00 <josie> stickies-v: yep! this is a big improvement over CMS(V)'s brute force approach
121 18:01 <stickies-v> I still think that the only way for `multi_a` to not pop anything off the stack is for it to be `multi_a(0)`?
122 18:01 <josie> okay, thanks everyone for attending and keep your eyes out for a follow-up!
123 18:01 <stickies-v> (i.e. k is 0 as per the first argument and n is 0 because we don't pass any further keys)
124 18:01 <josie> #endmeeting