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