/bitcoin/src/script/miniscript.cpp
Line | Count | Source |
1 | | // Copyright (c) 2019-present The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #include <limits> |
6 | | #include <vector> |
7 | | |
8 | | #include <primitives/transaction.h> |
9 | | #include <script/miniscript.h> |
10 | | #include <script/script.h> |
11 | | #include <script/solver.h> |
12 | | #include <span.h> |
13 | | #include <util/check.h> |
14 | | #include <util/vector.h> |
15 | | |
16 | | namespace miniscript { |
17 | | namespace internal { |
18 | | |
19 | 0 | Type SanitizeType(Type e) { |
20 | 0 | int num_types = (e << "K"_mst) + (e << "V"_mst) + (e << "B"_mst) + (e << "W"_mst); |
21 | 0 | if (num_types == 0) return ""_mst; // No valid type, don't care about the rest Branch (21:9): [True: 0, False: 0]
|
22 | 0 | CHECK_NONFATAL(num_types == 1); // K, V, B, W all conflict with each other |
23 | 0 | CHECK_NONFATAL(!(e << "z"_mst) || !(e << "o"_mst)); // z conflicts with o |
24 | 0 | CHECK_NONFATAL(!(e << "n"_mst) || !(e << "z"_mst)); // n conflicts with z |
25 | 0 | CHECK_NONFATAL(!(e << "n"_mst) || !(e << "W"_mst)); // n conflicts with W |
26 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || !(e << "d"_mst)); // V conflicts with d |
27 | 0 | CHECK_NONFATAL(!(e << "K"_mst) || (e << "u"_mst)); // K implies u |
28 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || !(e << "u"_mst)); // V conflicts with u |
29 | 0 | CHECK_NONFATAL(!(e << "e"_mst) || !(e << "f"_mst)); // e conflicts with f |
30 | 0 | CHECK_NONFATAL(!(e << "e"_mst) || (e << "d"_mst)); // e implies d |
31 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || !(e << "e"_mst)); // V conflicts with e |
32 | 0 | CHECK_NONFATAL(!(e << "d"_mst) || !(e << "f"_mst)); // d conflicts with f |
33 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || (e << "f"_mst)); // V implies f |
34 | 0 | CHECK_NONFATAL(!(e << "K"_mst) || (e << "s"_mst)); // K implies s |
35 | 0 | CHECK_NONFATAL(!(e << "z"_mst) || (e << "m"_mst)); // z implies m |
36 | 0 | return e; |
37 | 0 | } |
38 | | |
39 | | Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Type>& sub_types, uint32_t k, |
40 | 0 | size_t data_size, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx) { |
41 | | // Sanity check on data |
42 | 0 | if (fragment == Fragment::SHA256 || fragment == Fragment::HASH256) { Branch (42:9): [True: 0, False: 0]
Branch (42:41): [True: 0, False: 0]
|
43 | 0 | CHECK_NONFATAL(data_size == 32); |
44 | 0 | } else if (fragment == Fragment::RIPEMD160 || fragment == Fragment::HASH160) { Branch (44:16): [True: 0, False: 0]
Branch (44:51): [True: 0, False: 0]
|
45 | 0 | CHECK_NONFATAL(data_size == 20); |
46 | 0 | } else { |
47 | 0 | CHECK_NONFATAL(data_size == 0); |
48 | 0 | } |
49 | | // Sanity check on k |
50 | 0 | if (fragment == Fragment::OLDER || fragment == Fragment::AFTER) { Branch (50:9): [True: 0, False: 0]
Branch (50:40): [True: 0, False: 0]
|
51 | 0 | CHECK_NONFATAL(k >= 1 && k < 0x80000000UL); |
52 | 0 | } else if (fragment == Fragment::MULTI || fragment == Fragment::MULTI_A) { Branch (52:16): [True: 0, False: 0]
Branch (52:47): [True: 0, False: 0]
|
53 | 0 | CHECK_NONFATAL(k >= 1 && k <= n_keys); |
54 | 0 | } else if (fragment == Fragment::THRESH) { Branch (54:16): [True: 0, False: 0]
|
55 | 0 | CHECK_NONFATAL(k >= 1 && k <= n_subs); |
56 | 0 | } else { |
57 | 0 | CHECK_NONFATAL(k == 0); |
58 | 0 | } |
59 | | // Sanity check on subs |
60 | 0 | if (fragment == Fragment::AND_V || fragment == Fragment::AND_B || fragment == Fragment::OR_B || Branch (60:9): [True: 0, False: 0]
Branch (60:40): [True: 0, False: 0]
Branch (60:71): [True: 0, False: 0]
|
61 | 0 | fragment == Fragment::OR_C || fragment == Fragment::OR_I || fragment == Fragment::OR_D) { Branch (61:9): [True: 0, False: 0]
Branch (61:39): [True: 0, False: 0]
Branch (61:69): [True: 0, False: 0]
|
62 | 0 | CHECK_NONFATAL(n_subs == 2); |
63 | 0 | } else if (fragment == Fragment::ANDOR) { Branch (63:16): [True: 0, False: 0]
|
64 | 0 | CHECK_NONFATAL(n_subs == 3); |
65 | 0 | } else if (fragment == Fragment::WRAP_A || fragment == Fragment::WRAP_S || fragment == Fragment::WRAP_C || Branch (65:16): [True: 0, False: 0]
Branch (65:48): [True: 0, False: 0]
Branch (65:80): [True: 0, False: 0]
|
66 | 0 | fragment == Fragment::WRAP_D || fragment == Fragment::WRAP_V || fragment == Fragment::WRAP_J || Branch (66:16): [True: 0, False: 0]
Branch (66:48): [True: 0, False: 0]
Branch (66:80): [True: 0, False: 0]
|
67 | 0 | fragment == Fragment::WRAP_N) { Branch (67:16): [True: 0, False: 0]
|
68 | 0 | CHECK_NONFATAL(n_subs == 1); |
69 | 0 | } else if (fragment != Fragment::THRESH) { Branch (69:16): [True: 0, False: 0]
|
70 | 0 | CHECK_NONFATAL(n_subs == 0); |
71 | 0 | } |
72 | | // Sanity check on keys |
73 | 0 | if (fragment == Fragment::PK_K || fragment == Fragment::PK_H) { Branch (73:9): [True: 0, False: 0]
Branch (73:39): [True: 0, False: 0]
|
74 | 0 | CHECK_NONFATAL(n_keys == 1); |
75 | 0 | } else if (fragment == Fragment::MULTI) { Branch (75:16): [True: 0, False: 0]
|
76 | 0 | CHECK_NONFATAL(n_keys >= 1 && n_keys <= MAX_PUBKEYS_PER_MULTISIG); |
77 | 0 | CHECK_NONFATAL(!IsTapscript(ms_ctx)); |
78 | 0 | } else if (fragment == Fragment::MULTI_A) { Branch (78:16): [True: 0, False: 0]
|
79 | 0 | CHECK_NONFATAL(n_keys >= 1 && n_keys <= MAX_PUBKEYS_PER_MULTI_A); |
80 | 0 | CHECK_NONFATAL(IsTapscript(ms_ctx)); |
81 | 0 | } else { |
82 | 0 | CHECK_NONFATAL(n_keys == 0); |
83 | 0 | } |
84 | | |
85 | | // Below is the per-fragment logic for computing the expression types. |
86 | | // It heavily relies on Type's << operator (where "X << a_mst" means |
87 | | // "X has all properties listed in a"). |
88 | 0 | switch (fragment) { Branch (88:13): [True: 0, False: 0]
|
89 | 0 | case Fragment::PK_K: return "Konudemsxk"_mst; Branch (89:9): [True: 0, False: 0]
|
90 | 0 | case Fragment::PK_H: return "Knudemsxk"_mst; Branch (90:9): [True: 0, False: 0]
|
91 | 0 | case Fragment::OLDER: return Branch (91:9): [True: 0, False: 0]
|
92 | 0 | "g"_mst.If(k & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) | |
93 | 0 | "h"_mst.If(!(k & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG)) | |
94 | 0 | "Bzfmxk"_mst; |
95 | 0 | case Fragment::AFTER: return Branch (95:9): [True: 0, False: 0]
|
96 | 0 | "i"_mst.If(k >= LOCKTIME_THRESHOLD) | |
97 | 0 | "j"_mst.If(k < LOCKTIME_THRESHOLD) | |
98 | 0 | "Bzfmxk"_mst; |
99 | 0 | case Fragment::SHA256: return "Bonudmk"_mst; Branch (99:9): [True: 0, False: 0]
|
100 | 0 | case Fragment::RIPEMD160: return "Bonudmk"_mst; Branch (100:9): [True: 0, False: 0]
|
101 | 0 | case Fragment::HASH256: return "Bonudmk"_mst; Branch (101:9): [True: 0, False: 0]
|
102 | 0 | case Fragment::HASH160: return "Bonudmk"_mst; Branch (102:9): [True: 0, False: 0]
|
103 | 0 | case Fragment::JUST_1: return "Bzufmxk"_mst; Branch (103:9): [True: 0, False: 0]
|
104 | 0 | case Fragment::JUST_0: return "Bzudemsxk"_mst; Branch (104:9): [True: 0, False: 0]
|
105 | 0 | case Fragment::WRAP_A: return Branch (105:9): [True: 0, False: 0]
|
106 | 0 | "W"_mst.If(x << "B"_mst) | // W=B_x |
107 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
108 | 0 | (x & "udfems"_mst) | // u=u_x, d=d_x, f=f_x, e=e_x, m=m_x, s=s_x |
109 | 0 | "x"_mst; // x |
110 | 0 | case Fragment::WRAP_S: return Branch (110:9): [True: 0, False: 0]
|
111 | 0 | "W"_mst.If(x << "Bo"_mst) | // W=B_x*o_x |
112 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
113 | 0 | (x & "udfemsx"_mst); // u=u_x, d=d_x, f=f_x, e=e_x, m=m_x, s=s_x, x=x_x |
114 | 0 | case Fragment::WRAP_C: return Branch (114:9): [True: 0, False: 0]
|
115 | 0 | "B"_mst.If(x << "K"_mst) | // B=K_x |
116 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
117 | 0 | (x & "ondfem"_mst) | // o=o_x, n=n_x, d=d_x, f=f_x, e=e_x, m=m_x |
118 | 0 | "us"_mst; // u, s |
119 | 0 | case Fragment::WRAP_D: return Branch (119:9): [True: 0, False: 0]
|
120 | 0 | "B"_mst.If(x << "Vz"_mst) | // B=V_x*z_x |
121 | 0 | "o"_mst.If(x << "z"_mst) | // o=z_x |
122 | 0 | "e"_mst.If(x << "f"_mst) | // e=f_x |
123 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
124 | 0 | (x & "ms"_mst) | // m=m_x, s=s_x |
125 | | // NOTE: 'd:' is 'u' under Tapscript but not P2WSH as MINIMALIF is only a policy rule there. |
126 | 0 | "u"_mst.If(IsTapscript(ms_ctx)) | |
127 | 0 | "ndx"_mst; // n, d, x |
128 | 0 | case Fragment::WRAP_V: return Branch (128:9): [True: 0, False: 0]
|
129 | 0 | "V"_mst.If(x << "B"_mst) | // V=B_x |
130 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
131 | 0 | (x & "zonms"_mst) | // z=z_x, o=o_x, n=n_x, m=m_x, s=s_x |
132 | 0 | "fx"_mst; // f, x |
133 | 0 | case Fragment::WRAP_J: return Branch (133:9): [True: 0, False: 0]
|
134 | 0 | "B"_mst.If(x << "Bn"_mst) | // B=B_x*n_x |
135 | 0 | "e"_mst.If(x << "f"_mst) | // e=f_x |
136 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
137 | 0 | (x & "oums"_mst) | // o=o_x, u=u_x, m=m_x, s=s_x |
138 | 0 | "ndx"_mst; // n, d, x |
139 | 0 | case Fragment::WRAP_N: return Branch (139:9): [True: 0, False: 0]
|
140 | 0 | (x & "ghijk"_mst) | // g=g_x, h=h_x, i=i_x, j=j_x, k=k_x |
141 | 0 | (x & "Bzondfems"_mst) | // B=B_x, z=z_x, o=o_x, n=n_x, d=d_x, f=f_x, e=e_x, m=m_x, s=s_x |
142 | 0 | "ux"_mst; // u, x |
143 | 0 | case Fragment::AND_V: return Branch (143:9): [True: 0, False: 0]
|
144 | 0 | (y & "KVB"_mst).If(x << "V"_mst) | // B=V_x*B_y, V=V_x*V_y, K=V_x*K_y |
145 | 0 | (x & "n"_mst) | (y & "n"_mst).If(x << "z"_mst) | // n=n_x+z_x*n_y |
146 | 0 | ((x | y) & "o"_mst).If((x | y) << "z"_mst) | // o=o_x*z_y+z_x*o_y |
147 | 0 | (x & y & "dmz"_mst) | // d=d_x*d_y, m=m_x*m_y, z=z_x*z_y |
148 | 0 | ((x | y) & "s"_mst) | // s=s_x+s_y |
149 | 0 | "f"_mst.If((y << "f"_mst) || (x << "s"_mst)) | // f=f_y+s_x Branch (149:24): [True: 0, False: 0]
Branch (149:42): [True: 0, False: 0]
|
150 | 0 | (y & "ux"_mst) | // u=u_y, x=x_y |
151 | 0 | ((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y |
152 | 0 | "k"_mst.If(((x & y) << "k"_mst) && Branch (152:24): [True: 0, False: 0]
|
153 | 0 | !(((x << "g"_mst) && (y << "h"_mst)) || Branch (153:20): [True: 0, False: 0]
Branch (153:38): [True: 0, False: 0]
|
154 | 0 | ((x << "h"_mst) && (y << "g"_mst)) || Branch (154:18): [True: 0, False: 0]
Branch (154:36): [True: 0, False: 0]
|
155 | 0 | ((x << "i"_mst) && (y << "j"_mst)) || Branch (155:18): [True: 0, False: 0]
Branch (155:36): [True: 0, False: 0]
|
156 | 0 | ((x << "j"_mst) && (y << "i"_mst)))); // k=k_x*k_y*!(g_x*h_y + h_x*g_y + i_x*j_y + j_x*i_y) Branch (156:18): [True: 0, False: 0]
Branch (156:36): [True: 0, False: 0]
|
157 | 0 | case Fragment::AND_B: return Branch (157:9): [True: 0, False: 0]
|
158 | 0 | (x & "B"_mst).If(y << "W"_mst) | // B=B_x*W_y |
159 | 0 | ((x | y) & "o"_mst).If((x | y) << "z"_mst) | // o=o_x*z_y+z_x*o_y |
160 | 0 | (x & "n"_mst) | (y & "n"_mst).If(x << "z"_mst) | // n=n_x+z_x*n_y |
161 | 0 | (x & y & "e"_mst).If((x & y) << "s"_mst) | // e=e_x*e_y*s_x*s_y |
162 | 0 | (x & y & "dzm"_mst) | // d=d_x*d_y, z=z_x*z_y, m=m_x*m_y |
163 | 0 | "f"_mst.If(((x & y) << "f"_mst) || (x << "sf"_mst) || (y << "sf"_mst)) | // f=f_x*f_y + f_x*s_x + f_y*s_y Branch (163:24): [True: 0, False: 0]
Branch (163:48): [True: 0, False: 0]
Branch (163:67): [True: 0, False: 0]
|
164 | 0 | ((x | y) & "s"_mst) | // s=s_x+s_y |
165 | 0 | "ux"_mst | // u, x |
166 | 0 | ((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y |
167 | 0 | "k"_mst.If(((x & y) << "k"_mst) && Branch (167:24): [True: 0, False: 0]
|
168 | 0 | !(((x << "g"_mst) && (y << "h"_mst)) || Branch (168:20): [True: 0, False: 0]
Branch (168:38): [True: 0, False: 0]
|
169 | 0 | ((x << "h"_mst) && (y << "g"_mst)) || Branch (169:18): [True: 0, False: 0]
Branch (169:36): [True: 0, False: 0]
|
170 | 0 | ((x << "i"_mst) && (y << "j"_mst)) || Branch (170:18): [True: 0, False: 0]
Branch (170:36): [True: 0, False: 0]
|
171 | 0 | ((x << "j"_mst) && (y << "i"_mst)))); // k=k_x*k_y*!(g_x*h_y + h_x*g_y + i_x*j_y + j_x*i_y) Branch (171:18): [True: 0, False: 0]
Branch (171:36): [True: 0, False: 0]
|
172 | 0 | case Fragment::OR_B: return Branch (172:9): [True: 0, False: 0]
|
173 | 0 | "B"_mst.If(x << "Bd"_mst && y << "Wd"_mst) | // B=B_x*d_x*W_x*d_y Branch (173:24): [True: 0, False: 0]
Branch (173:41): [True: 0, False: 0]
|
174 | 0 | ((x | y) & "o"_mst).If((x | y) << "z"_mst) | // o=o_x*z_y+z_x*o_y |
175 | 0 | (x & y & "m"_mst).If((x | y) << "s"_mst && (x & y) << "e"_mst) | // m=m_x*m_y*e_x*e_y*(s_x+s_y) Branch (175:34): [True: 0, False: 0]
Branch (175:56): [True: 0, False: 0]
|
176 | 0 | (x & y & "zse"_mst) | // z=z_x*z_y, s=s_x*s_y, e=e_x*e_y |
177 | 0 | "dux"_mst | // d, u, x |
178 | 0 | ((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y |
179 | 0 | (x & y & "k"_mst); // k=k_x*k_y |
180 | 0 | case Fragment::OR_D: return Branch (180:9): [True: 0, False: 0]
|
181 | 0 | (y & "B"_mst).If(x << "Bdu"_mst) | // B=B_y*B_x*d_x*u_x |
182 | 0 | (x & "o"_mst).If(y << "z"_mst) | // o=o_x*z_y |
183 | 0 | (x & y & "m"_mst).If(x << "e"_mst && (x | y) << "s"_mst) | // m=m_x*m_y*e_x*(s_x+s_y) Branch (183:34): [True: 0, False: 0]
Branch (183:50): [True: 0, False: 0]
|
184 | 0 | (x & y & "zs"_mst) | // z=z_x*z_y, s=s_x*s_y |
185 | 0 | (y & "ufde"_mst) | // u=u_y, f=f_y, d=d_y, e=e_y |
186 | 0 | "x"_mst | // x |
187 | 0 | ((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y |
188 | 0 | (x & y & "k"_mst); // k=k_x*k_y |
189 | 0 | case Fragment::OR_C: return Branch (189:9): [True: 0, False: 0]
|
190 | 0 | (y & "V"_mst).If(x << "Bdu"_mst) | // V=V_y*B_x*u_x*d_x |
191 | 0 | (x & "o"_mst).If(y << "z"_mst) | // o=o_x*z_y |
192 | 0 | (x & y & "m"_mst).If(x << "e"_mst && (x | y) << "s"_mst) | // m=m_x*m_y*e_x*(s_x+s_y) Branch (192:34): [True: 0, False: 0]
Branch (192:50): [True: 0, False: 0]
|
193 | 0 | (x & y & "zs"_mst) | // z=z_x*z_y, s=s_x*s_y |
194 | 0 | "fx"_mst | // f, x |
195 | 0 | ((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y |
196 | 0 | (x & y & "k"_mst); // k=k_x*k_y |
197 | 0 | case Fragment::OR_I: return Branch (197:9): [True: 0, False: 0]
|
198 | 0 | (x & y & "VBKufs"_mst) | // V=V_x*V_y, B=B_x*B_y, K=K_x*K_y, u=u_x*u_y, f=f_x*f_y, s=s_x*s_y |
199 | 0 | "o"_mst.If((x & y) << "z"_mst) | // o=z_x*z_y |
200 | 0 | ((x | y) & "e"_mst).If((x | y) << "f"_mst) | // e=e_x*f_y+f_x*e_y |
201 | 0 | (x & y & "m"_mst).If((x | y) << "s"_mst) | // m=m_x*m_y*(s_x+s_y) |
202 | 0 | ((x | y) & "d"_mst) | // d=d_x+d_y |
203 | 0 | "x"_mst | // x |
204 | 0 | ((x | y) & "ghij"_mst) | // g=g_x+g_y, h=h_x+h_y, i=i_x+i_y, j=j_x+j_y |
205 | 0 | (x & y & "k"_mst); // k=k_x*k_y |
206 | 0 | case Fragment::ANDOR: return Branch (206:9): [True: 0, False: 0]
|
207 | 0 | (y & z & "BKV"_mst).If(x << "Bdu"_mst) | // B=B_x*d_x*u_x*B_y*B_z, K=B_x*d_x*u_x*K_y*K_z, V=B_x*d_x*u_x*V_y*V_z |
208 | 0 | (x & y & z & "z"_mst) | // z=z_x*z_y*z_z |
209 | 0 | ((x | (y & z)) & "o"_mst).If((x | (y & z)) << "z"_mst) | // o=o_x*z_y*z_z+z_x*o_y*o_z |
210 | 0 | (y & z & "u"_mst) | // u=u_y*u_z |
211 | 0 | (z & "f"_mst).If((x << "s"_mst) || (y << "f"_mst)) | // f=(s_x+f_y)*f_z Branch (211:30): [True: 0, False: 0]
Branch (211:48): [True: 0, False: 0]
|
212 | 0 | (z & "d"_mst) | // d=d_z |
213 | 0 | (z & "e"_mst).If(x << "s"_mst || y << "f"_mst) | // e=e_z*(s_x+f_y) Branch (213:30): [True: 0, False: 0]
Branch (213:46): [True: 0, False: 0]
|
214 | 0 | (x & y & z & "m"_mst).If(x << "e"_mst && (x | y | z) << "s"_mst) | // m=m_x*m_y*m_z*e_x*(s_x+s_y+s_z) Branch (214:38): [True: 0, False: 0]
Branch (214:54): [True: 0, False: 0]
|
215 | 0 | (z & (x | y) & "s"_mst) | // s=s_z*(s_x+s_y) |
216 | 0 | "x"_mst | // x |
217 | 0 | ((x | y | z) & "ghij"_mst) | // g=g_x+g_y+g_z, h=h_x+h_y+h_z, i=i_x+i_y+i_z, j=j_x+j_y_j_z |
218 | 0 | "k"_mst.If(((x & y & z) << "k"_mst) && Branch (218:24): [True: 0, False: 0]
|
219 | 0 | !(((x << "g"_mst) && (y << "h"_mst)) || Branch (219:20): [True: 0, False: 0]
Branch (219:38): [True: 0, False: 0]
|
220 | 0 | ((x << "h"_mst) && (y << "g"_mst)) || Branch (220:18): [True: 0, False: 0]
Branch (220:36): [True: 0, False: 0]
|
221 | 0 | ((x << "i"_mst) && (y << "j"_mst)) || Branch (221:18): [True: 0, False: 0]
Branch (221:36): [True: 0, False: 0]
|
222 | 0 | ((x << "j"_mst) && (y << "i"_mst)))); // k=k_x*k_y*k_z* !(g_x*h_y + h_x*g_y + i_x*j_y + j_x*i_y) Branch (222:18): [True: 0, False: 0]
Branch (222:36): [True: 0, False: 0]
|
223 | 0 | case Fragment::MULTI: { Branch (223:9): [True: 0, False: 0]
|
224 | 0 | return "Bnudemsk"_mst; |
225 | 0 | } |
226 | 0 | case Fragment::MULTI_A: { Branch (226:9): [True: 0, False: 0]
|
227 | 0 | return "Budemsk"_mst; |
228 | 0 | } |
229 | 0 | case Fragment::THRESH: { Branch (229:9): [True: 0, False: 0]
|
230 | 0 | bool all_e = true; |
231 | 0 | bool all_m = true; |
232 | 0 | uint32_t args = 0; |
233 | 0 | uint32_t num_s = 0; |
234 | 0 | Type acc_tl = "k"_mst; |
235 | 0 | for (size_t i = 0; i < sub_types.size(); ++i) { Branch (235:32): [True: 0, False: 0]
|
236 | 0 | Type t = sub_types[i]; |
237 | 0 | static constexpr auto WDU{"Wdu"_mst}, BDU{"Bdu"_mst}; |
238 | 0 | if (!(t << (i ? WDU : BDU))) return ""_mst; // Require Bdu, Wdu, Wdu, ... Branch (238:21): [True: 0, False: 0]
Branch (238:29): [True: 0, False: 0]
|
239 | 0 | if (!(t << "e"_mst)) all_e = false; Branch (239:21): [True: 0, False: 0]
|
240 | 0 | if (!(t << "m"_mst)) all_m = false; Branch (240:21): [True: 0, False: 0]
|
241 | 0 | if (t << "s"_mst) num_s += 1; Branch (241:21): [True: 0, False: 0]
|
242 | 0 | args += (t << "z"_mst) ? 0 : (t << "o"_mst) ? 1 : 2; Branch (242:25): [True: 0, False: 0]
Branch (242:46): [True: 0, False: 0]
|
243 | 0 | acc_tl = ((acc_tl | t) & "ghij"_mst) | |
244 | | // Thresh contains a combination of timelocks if it has threshold > 1 and |
245 | | // it contains two different children that have different types of timelocks |
246 | | // Note how if any of the children don't have "k", the parent also does not have "k" |
247 | 0 | "k"_mst.If(((acc_tl & t) << "k"_mst) && ((k <= 1) || Branch (247:32): [True: 0, False: 0]
Branch (247:62): [True: 0, False: 0]
|
248 | 0 | ((k > 1) && !(((acc_tl << "g"_mst) && (t << "h"_mst)) || Branch (248:26): [True: 0, False: 0]
Branch (248:40): [True: 0, False: 0]
Branch (248:63): [True: 0, False: 0]
|
249 | 0 | ((acc_tl << "h"_mst) && (t << "g"_mst)) || Branch (249:26): [True: 0, False: 0]
Branch (249:49): [True: 0, False: 0]
|
250 | 0 | ((acc_tl << "i"_mst) && (t << "j"_mst)) || Branch (250:26): [True: 0, False: 0]
Branch (250:49): [True: 0, False: 0]
|
251 | 0 | ((acc_tl << "j"_mst) && (t << "i"_mst)))))); Branch (251:26): [True: 0, False: 0]
Branch (251:49): [True: 0, False: 0]
|
252 | 0 | } |
253 | 0 | return "Bdu"_mst | |
254 | 0 | "z"_mst.If(args == 0) | // z=all z |
255 | 0 | "o"_mst.If(args == 1) | // o=all z except one o |
256 | 0 | "e"_mst.If(all_e && num_s == n_subs) | // e=all e and all s Branch (256:31): [True: 0, False: 0]
Branch (256:40): [True: 0, False: 0]
|
257 | 0 | "m"_mst.If(all_e && all_m && num_s >= n_subs - k) | // m=all e, >=(n-k) s Branch (257:31): [True: 0, False: 0]
Branch (257:40): [True: 0, False: 0]
Branch (257:49): [True: 0, False: 0]
|
258 | 0 | "s"_mst.If(num_s >= n_subs - k + 1) | // s= >=(n-k+1) s |
259 | 0 | acc_tl; // timelock info |
260 | 0 | } |
261 | 0 | } |
262 | 0 | assert(false); Branch (262:5): [Folded - Ignored]
|
263 | 0 | } |
264 | | |
265 | | size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, |
266 | 0 | size_t n_keys, MiniscriptContext ms_ctx) { |
267 | 0 | switch (fragment) { Branch (267:13): [True: 0, False: 0]
|
268 | 0 | case Fragment::JUST_1: Branch (268:9): [True: 0, False: 0]
|
269 | 0 | case Fragment::JUST_0: return 1; Branch (269:9): [True: 0, False: 0]
|
270 | 0 | case Fragment::PK_K: return IsTapscript(ms_ctx) ? 33 : 34; Branch (270:9): [True: 0, False: 0]
Branch (270:37): [True: 0, False: 0]
|
271 | 0 | case Fragment::PK_H: return 3 + 21; Branch (271:9): [True: 0, False: 0]
|
272 | 0 | case Fragment::OLDER: Branch (272:9): [True: 0, False: 0]
|
273 | 0 | case Fragment::AFTER: return 1 + BuildScript(k).size(); Branch (273:9): [True: 0, False: 0]
|
274 | 0 | case Fragment::HASH256: Branch (274:9): [True: 0, False: 0]
|
275 | 0 | case Fragment::SHA256: return 4 + 2 + 33; Branch (275:9): [True: 0, False: 0]
|
276 | 0 | case Fragment::HASH160: Branch (276:9): [True: 0, False: 0]
|
277 | 0 | case Fragment::RIPEMD160: return 4 + 2 + 21; Branch (277:9): [True: 0, False: 0]
|
278 | 0 | case Fragment::MULTI: return 1 + BuildScript(n_keys).size() + BuildScript(k).size() + 34 * n_keys; Branch (278:9): [True: 0, False: 0]
|
279 | 0 | case Fragment::MULTI_A: return (1 + 32 + 1) * n_keys + BuildScript(k).size() + 1; Branch (279:9): [True: 0, False: 0]
|
280 | 0 | case Fragment::AND_V: return subsize; Branch (280:9): [True: 0, False: 0]
|
281 | 0 | case Fragment::WRAP_V: return subsize + (sub0typ << "x"_mst); Branch (281:9): [True: 0, False: 0]
|
282 | 0 | case Fragment::WRAP_S: Branch (282:9): [True: 0, False: 0]
|
283 | 0 | case Fragment::WRAP_C: Branch (283:9): [True: 0, False: 0]
|
284 | 0 | case Fragment::WRAP_N: Branch (284:9): [True: 0, False: 0]
|
285 | 0 | case Fragment::AND_B: Branch (285:9): [True: 0, False: 0]
|
286 | 0 | case Fragment::OR_B: return subsize + 1; Branch (286:9): [True: 0, False: 0]
|
287 | 0 | case Fragment::WRAP_A: Branch (287:9): [True: 0, False: 0]
|
288 | 0 | case Fragment::OR_C: return subsize + 2; Branch (288:9): [True: 0, False: 0]
|
289 | 0 | case Fragment::WRAP_D: Branch (289:9): [True: 0, False: 0]
|
290 | 0 | case Fragment::OR_D: Branch (290:9): [True: 0, False: 0]
|
291 | 0 | case Fragment::OR_I: Branch (291:9): [True: 0, False: 0]
|
292 | 0 | case Fragment::ANDOR: return subsize + 3; Branch (292:9): [True: 0, False: 0]
|
293 | 0 | case Fragment::WRAP_J: return subsize + 4; Branch (293:9): [True: 0, False: 0]
|
294 | 0 | case Fragment::THRESH: return subsize + n_subs + BuildScript(k).size(); Branch (294:9): [True: 0, False: 0]
|
295 | 0 | } |
296 | 0 | assert(false); Branch (296:5): [Folded - Ignored]
|
297 | 0 | } |
298 | | |
299 | 33.2k | InputStack& InputStack::SetAvailable(Availability avail) { |
300 | 33.2k | available = avail; |
301 | 33.2k | if (avail == Availability::NO) { Branch (301:9): [True: 33.2k, False: 0]
|
302 | 33.2k | stack.clear(); |
303 | 33.2k | size = std::numeric_limits<size_t>::max(); |
304 | 33.2k | has_sig = false; |
305 | 33.2k | malleable = false; |
306 | 33.2k | non_canon = false; |
307 | 33.2k | } |
308 | 33.2k | return *this; |
309 | 33.2k | } |
310 | | |
311 | 0 | InputStack& InputStack::SetWithSig() { |
312 | 0 | has_sig = true; |
313 | 0 | return *this; |
314 | 0 | } |
315 | | |
316 | 0 | InputStack& InputStack::SetNonCanon() { |
317 | 0 | non_canon = true; |
318 | 0 | return *this; |
319 | 0 | } |
320 | | |
321 | 33.2k | InputStack& InputStack::SetMalleable(bool x) { |
322 | 33.2k | malleable = x; |
323 | 33.2k | return *this; |
324 | 33.2k | } |
325 | | |
326 | 0 | InputStack operator+(InputStack a, InputStack b) { |
327 | 0 | a.stack = Cat(std::move(a.stack), std::move(b.stack)); |
328 | 0 | if (a.available != Availability::NO && b.available != Availability::NO) a.size += b.size; Branch (328:9): [True: 0, False: 0]
Branch (328:44): [True: 0, False: 0]
|
329 | 0 | a.has_sig |= b.has_sig; |
330 | 0 | a.malleable |= b.malleable; |
331 | 0 | a.non_canon |= b.non_canon; |
332 | 0 | if (a.available == Availability::NO || b.available == Availability::NO) { Branch (332:9): [True: 0, False: 0]
Branch (332:44): [True: 0, False: 0]
|
333 | 0 | a.SetAvailable(Availability::NO); |
334 | 0 | } else if (a.available == Availability::MAYBE || b.available == Availability::MAYBE) { Branch (334:16): [True: 0, False: 0]
Branch (334:54): [True: 0, False: 0]
|
335 | 0 | a.SetAvailable(Availability::MAYBE); |
336 | 0 | } |
337 | 0 | return a; |
338 | 0 | } |
339 | | |
340 | 0 | InputStack operator|(InputStack a, InputStack b) { |
341 | | // If only one is invalid, pick the other one. If both are invalid, pick an arbitrary one. |
342 | 0 | if (a.available == Availability::NO) return b; Branch (342:9): [True: 0, False: 0]
|
343 | 0 | if (b.available == Availability::NO) return a; Branch (343:9): [True: 0, False: 0]
|
344 | | // If only one of the solutions has a signature, we must pick the other one. |
345 | 0 | if (!a.has_sig && b.has_sig) return a; Branch (345:9): [True: 0, False: 0]
Branch (345:23): [True: 0, False: 0]
|
346 | 0 | if (!b.has_sig && a.has_sig) return b; Branch (346:9): [True: 0, False: 0]
Branch (346:23): [True: 0, False: 0]
|
347 | 0 | if (!a.has_sig && !b.has_sig) { Branch (347:9): [True: 0, False: 0]
Branch (347:23): [True: 0, False: 0]
|
348 | | // If neither solution requires a signature, the result is inevitably malleable. |
349 | 0 | a.malleable = true; |
350 | 0 | b.malleable = true; |
351 | 0 | } else { |
352 | | // If both options require a signature, prefer the non-malleable one. |
353 | 0 | if (b.malleable && !a.malleable) return a; Branch (353:13): [True: 0, False: 0]
Branch (353:28): [True: 0, False: 0]
|
354 | 0 | if (a.malleable && !b.malleable) return b; Branch (354:13): [True: 0, False: 0]
Branch (354:28): [True: 0, False: 0]
|
355 | 0 | } |
356 | | // Between two malleable or two non-malleable solutions, pick the smaller one between |
357 | | // YESes, and the bigger ones between MAYBEs. Prefer YES over MAYBE. |
358 | 0 | if (a.available == Availability::YES && b.available == Availability::YES) { Branch (358:9): [True: 0, False: 0]
Branch (358:45): [True: 0, False: 0]
|
359 | 0 | return std::move(a.size <= b.size ? a : b); Branch (359:26): [True: 0, False: 0]
|
360 | 0 | } else if (a.available == Availability::MAYBE && b.available == Availability::MAYBE) { Branch (360:16): [True: 0, False: 0]
Branch (360:54): [True: 0, False: 0]
|
361 | 0 | return std::move(a.size >= b.size ? a : b); Branch (361:26): [True: 0, False: 0]
|
362 | 0 | } else if (a.available == Availability::YES) { Branch (362:16): [True: 0, False: 0]
|
363 | 0 | return a; |
364 | 0 | } else { |
365 | 0 | return b; |
366 | 0 | } |
367 | 0 | } |
368 | | |
369 | | std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script) |
370 | 0 | { |
371 | 0 | std::vector<Opcode> out; |
372 | 0 | CScript::const_iterator it = script.begin(), itend = script.end(); |
373 | 0 | while (it != itend) { Branch (373:12): [True: 0, False: 0]
|
374 | 0 | std::vector<unsigned char> push_data; |
375 | 0 | opcodetype opcode; |
376 | 0 | if (!script.GetOp(it, opcode, push_data)) { Branch (376:13): [True: 0, False: 0]
|
377 | 0 | return {}; |
378 | 0 | } else if (opcode >= OP_1 && opcode <= OP_16) { Branch (378:20): [True: 0, False: 0]
Branch (378:38): [True: 0, False: 0]
|
379 | | // Deal with OP_n (GetOp does not turn them into pushes). |
380 | 0 | push_data.assign(1, CScript::DecodeOP_N(opcode)); |
381 | 0 | } else if (opcode == OP_CHECKSIGVERIFY) { Branch (381:20): [True: 0, False: 0]
|
382 | | // Decompose OP_CHECKSIGVERIFY into OP_CHECKSIG OP_VERIFY |
383 | 0 | out.emplace_back(OP_CHECKSIG, std::vector<unsigned char>()); |
384 | 0 | opcode = OP_VERIFY; |
385 | 0 | } else if (opcode == OP_CHECKMULTISIGVERIFY) { Branch (385:20): [True: 0, False: 0]
|
386 | | // Decompose OP_CHECKMULTISIGVERIFY into OP_CHECKMULTISIG OP_VERIFY |
387 | 0 | out.emplace_back(OP_CHECKMULTISIG, std::vector<unsigned char>()); |
388 | 0 | opcode = OP_VERIFY; |
389 | 0 | } else if (opcode == OP_EQUALVERIFY) { Branch (389:20): [True: 0, False: 0]
|
390 | | // Decompose OP_EQUALVERIFY into OP_EQUAL OP_VERIFY |
391 | 0 | out.emplace_back(OP_EQUAL, std::vector<unsigned char>()); |
392 | 0 | opcode = OP_VERIFY; |
393 | 0 | } else if (opcode == OP_NUMEQUALVERIFY) { Branch (393:20): [True: 0, False: 0]
|
394 | | // Decompose OP_NUMEQUALVERIFY into OP_NUMEQUAL OP_VERIFY |
395 | 0 | out.emplace_back(OP_NUMEQUAL, std::vector<unsigned char>()); |
396 | 0 | opcode = OP_VERIFY; |
397 | 0 | } else if (IsPushdataOp(opcode)) { Branch (397:20): [True: 0, False: 0]
|
398 | 0 | if (!CheckMinimalPush(push_data, opcode)) return {}; Branch (398:17): [True: 0, False: 0]
|
399 | 0 | } else if (it != itend && (opcode == OP_CHECKSIG || opcode == OP_CHECKMULTISIG || opcode == OP_EQUAL || opcode == OP_NUMEQUAL) && (*it == OP_VERIFY)) { Branch (399:20): [True: 0, False: 0]
Branch (399:36): [True: 0, False: 0]
Branch (399:61): [True: 0, False: 0]
Branch (399:91): [True: 0, False: 0]
Branch (399:113): [True: 0, False: 0]
Branch (399:139): [True: 0, False: 0]
|
400 | | // Rule out non minimal VERIFY sequences |
401 | 0 | return {}; |
402 | 0 | } |
403 | 0 | out.emplace_back(opcode, std::move(push_data)); |
404 | 0 | } |
405 | 0 | std::reverse(out.begin(), out.end()); |
406 | 0 | return out; |
407 | 0 | } |
408 | | |
409 | 0 | std::optional<int64_t> ParseScriptNumber(const Opcode& in) { |
410 | 0 | if (in.first == OP_0) { Branch (410:9): [True: 0, False: 0]
|
411 | 0 | return 0; |
412 | 0 | } |
413 | 0 | if (!in.second.empty()) { Branch (413:9): [True: 0, False: 0]
|
414 | 0 | if (IsPushdataOp(in.first) && !CheckMinimalPush(in.second, in.first)) return {}; Branch (414:13): [True: 0, False: 0]
Branch (414:39): [True: 0, False: 0]
|
415 | 0 | try { |
416 | 0 | return CScriptNum(in.second, true).GetInt64(); |
417 | 0 | } catch(const scriptnum_error&) {} |
418 | 0 | } |
419 | 0 | return {}; |
420 | 0 | } |
421 | | |
422 | | int FindNextChar(std::span<const char> sp, const char m) |
423 | 0 | { |
424 | 0 | for (int i = 0; i < (int)sp.size(); ++i) { Branch (424:21): [True: 0, False: 0]
|
425 | 0 | if (sp[i] == m) return i; Branch (425:13): [True: 0, False: 0]
|
426 | | // We only search within the current parentheses |
427 | 0 | if (sp[i] == ')') break; Branch (427:13): [True: 0, False: 0]
|
428 | 0 | } |
429 | 0 | return -1; |
430 | 0 | } |
431 | | |
432 | | } // namespace internal |
433 | | } // namespace miniscript |