/Users/eugenesiegel/btc/bitcoin/src/script/miniscript.cpp
Line | Count | Source (jump to first uncovered line) |
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 |
22 | 0 | CHECK_NONFATAL(num_types == 1); // K, V, B, W all conflict with each other Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
23 | 0 | CHECK_NONFATAL(!(e << "z"_mst) || !(e << "o"_mst)); // z conflicts with o Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
24 | 0 | CHECK_NONFATAL(!(e << "n"_mst) || !(e << "z"_mst)); // n conflicts with z Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
25 | 0 | CHECK_NONFATAL(!(e << "n"_mst) || !(e << "W"_mst)); // n conflicts with W Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
26 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || !(e << "d"_mst)); // V conflicts with d Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
27 | 0 | CHECK_NONFATAL(!(e << "K"_mst) || (e << "u"_mst)); // K implies u Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
28 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || !(e << "u"_mst)); // V conflicts with u Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
29 | 0 | CHECK_NONFATAL(!(e << "e"_mst) || !(e << "f"_mst)); // e conflicts with f Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
30 | 0 | CHECK_NONFATAL(!(e << "e"_mst) || (e << "d"_mst)); // e implies d Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
31 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || !(e << "e"_mst)); // V conflicts with e Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
32 | 0 | CHECK_NONFATAL(!(e << "d"_mst) || !(e << "f"_mst)); // d conflicts with f Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
33 | 0 | CHECK_NONFATAL(!(e << "V"_mst) || (e << "f"_mst)); // V implies f Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
34 | 0 | CHECK_NONFATAL(!(e << "K"_mst) || (e << "s"_mst)); // K implies s Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
35 | 0 | CHECK_NONFATAL(!(e << "z"_mst) || (e << "m"_mst)); // z implies m Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
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) { |
43 | 0 | CHECK_NONFATAL(data_size == 32); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
44 | 0 | } else if (fragment == Fragment::RIPEMD160 || fragment == Fragment::HASH160) { |
45 | 0 | CHECK_NONFATAL(data_size == 20); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
46 | 0 | } else { |
47 | 0 | CHECK_NONFATAL(data_size == 0); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
48 | 0 | } |
49 | | // Sanity check on k |
50 | 0 | if (fragment == Fragment::OLDER || fragment == Fragment::AFTER) { |
51 | 0 | CHECK_NONFATAL(k >= 1 && k < 0x80000000UL); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
52 | 0 | } else if (fragment == Fragment::MULTI || fragment == Fragment::MULTI_A) { |
53 | 0 | CHECK_NONFATAL(k >= 1 && k <= n_keys); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
54 | 0 | } else if (fragment == Fragment::THRESH) { |
55 | 0 | CHECK_NONFATAL(k >= 1 && k <= n_subs); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
56 | 0 | } else { |
57 | 0 | CHECK_NONFATAL(k == 0); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
58 | 0 | } |
59 | | // Sanity check on subs |
60 | 0 | if (fragment == Fragment::AND_V || fragment == Fragment::AND_B || fragment == Fragment::OR_B || |
61 | 0 | fragment == Fragment::OR_C || fragment == Fragment::OR_I || fragment == Fragment::OR_D) { |
62 | 0 | CHECK_NONFATAL(n_subs == 2); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
63 | 0 | } else if (fragment == Fragment::ANDOR) { |
64 | 0 | CHECK_NONFATAL(n_subs == 3); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
65 | 0 | } else if (fragment == Fragment::WRAP_A || fragment == Fragment::WRAP_S || fragment == Fragment::WRAP_C || |
66 | 0 | fragment == Fragment::WRAP_D || fragment == Fragment::WRAP_V || fragment == Fragment::WRAP_J || |
67 | 0 | fragment == Fragment::WRAP_N) { |
68 | 0 | CHECK_NONFATAL(n_subs == 1); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
69 | 0 | } else if (fragment != Fragment::THRESH) { |
70 | 0 | CHECK_NONFATAL(n_subs == 0); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
71 | 0 | } |
72 | | // Sanity check on keys |
73 | 0 | if (fragment == Fragment::PK_K || fragment == Fragment::PK_H) { |
74 | 0 | CHECK_NONFATAL(n_keys == 1); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
75 | 0 | } else if (fragment == Fragment::MULTI) { |
76 | 0 | CHECK_NONFATAL(n_keys >= 1 && n_keys <= MAX_PUBKEYS_PER_MULTISIG); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
77 | 0 | CHECK_NONFATAL(!IsTapscript(ms_ctx)); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
78 | 0 | } else if (fragment == Fragment::MULTI_A) { |
79 | 0 | CHECK_NONFATAL(n_keys >= 1 && n_keys <= MAX_PUBKEYS_PER_MULTI_A); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
80 | 0 | CHECK_NONFATAL(IsTapscript(ms_ctx)); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
81 | 0 | } else { |
82 | 0 | CHECK_NONFATAL(n_keys == 0); Line | Count | Source | 103 | 0 | inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) |
|
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) { |
89 | 0 | case Fragment::PK_K: return "Konudemsxk"_mst; |
90 | 0 | case Fragment::PK_H: return "Knudemsxk"_mst; |
91 | 0 | case Fragment::OLDER: return |
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 |
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; |
100 | 0 | case Fragment::RIPEMD160: return "Bonudmk"_mst; |
101 | 0 | case Fragment::HASH256: return "Bonudmk"_mst; |
102 | 0 | case Fragment::HASH160: return "Bonudmk"_mst; |
103 | 0 | case Fragment::JUST_1: return "Bzufmxk"_mst; |
104 | 0 | case Fragment::JUST_0: return "Bzudemsxk"_mst; |
105 | 0 | case Fragment::WRAP_A: return |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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) && |
153 | 0 | !(((x << "g"_mst) && (y << "h"_mst)) || |
154 | 0 | ((x << "h"_mst) && (y << "g"_mst)) || |
155 | 0 | ((x << "i"_mst) && (y << "j"_mst)) || |
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) |
157 | 0 | case Fragment::AND_B: return |
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 |
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) && |
168 | 0 | !(((x << "g"_mst) && (y << "h"_mst)) || |
169 | 0 | ((x << "h"_mst) && (y << "g"_mst)) || |
170 | 0 | ((x << "i"_mst) && (y << "j"_mst)) || |
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) |
172 | 0 | case Fragment::OR_B: return |
173 | 0 | "B"_mst.If(x << "Bd"_mst && y << "Wd"_mst) | // B=B_x*d_x*W_x*d_y |
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) |
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 |
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) |
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 |
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) |
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 |
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 |
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 |
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) |
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) |
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) && |
219 | 0 | !(((x << "g"_mst) && (y << "h"_mst)) || |
220 | 0 | ((x << "h"_mst) && (y << "g"_mst)) || |
221 | 0 | ((x << "i"_mst) && (y << "j"_mst)) || |
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) |
223 | 0 | case Fragment::MULTI: { |
224 | 0 | return "Bnudemsk"_mst; |
225 | 0 | } |
226 | 0 | case Fragment::MULTI_A: { |
227 | 0 | return "Budemsk"_mst; |
228 | 0 | } |
229 | 0 | case Fragment::THRESH: { |
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) { |
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, ... |
239 | 0 | if (!(t << "e"_mst)) all_e = false; |
240 | 0 | if (!(t << "m"_mst)) all_m = false; |
241 | 0 | if (t << "s"_mst) num_s += 1; |
242 | 0 | args += (t << "z"_mst) ? 0 : (t << "o"_mst) ? 1 : 2; |
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) || |
248 | 0 | ((k > 1) && !(((acc_tl << "g"_mst) && (t << "h"_mst)) || |
249 | 0 | ((acc_tl << "h"_mst) && (t << "g"_mst)) || |
250 | 0 | ((acc_tl << "i"_mst) && (t << "j"_mst)) || |
251 | 0 | ((acc_tl << "j"_mst) && (t << "i"_mst)))))); |
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 |
257 | 0 | "m"_mst.If(all_e && all_m && num_s >= n_subs - k) | // m=all e, >=(n-k) s |
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); |
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) { |
268 | 0 | case Fragment::JUST_1: |
269 | 0 | case Fragment::JUST_0: return 1; |
270 | 0 | case Fragment::PK_K: return IsTapscript(ms_ctx) ? 33 : 34; |
271 | 0 | case Fragment::PK_H: return 3 + 21; |
272 | 0 | case Fragment::OLDER: |
273 | 0 | case Fragment::AFTER: return 1 + BuildScript(k).size(); |
274 | 0 | case Fragment::HASH256: |
275 | 0 | case Fragment::SHA256: return 4 + 2 + 33; |
276 | 0 | case Fragment::HASH160: |
277 | 0 | case Fragment::RIPEMD160: return 4 + 2 + 21; |
278 | 0 | case Fragment::MULTI: return 1 + BuildScript(n_keys).size() + BuildScript(k).size() + 34 * n_keys; |
279 | 0 | case Fragment::MULTI_A: return (1 + 32 + 1) * n_keys + BuildScript(k).size() + 1; |
280 | 0 | case Fragment::AND_V: return subsize; |
281 | 0 | case Fragment::WRAP_V: return subsize + (sub0typ << "x"_mst); |
282 | 0 | case Fragment::WRAP_S: |
283 | 0 | case Fragment::WRAP_C: |
284 | 0 | case Fragment::WRAP_N: |
285 | 0 | case Fragment::AND_B: |
286 | 0 | case Fragment::OR_B: return subsize + 1; |
287 | 0 | case Fragment::WRAP_A: |
288 | 0 | case Fragment::OR_C: return subsize + 2; |
289 | 0 | case Fragment::WRAP_D: |
290 | 0 | case Fragment::OR_D: |
291 | 0 | case Fragment::OR_I: |
292 | 0 | case Fragment::ANDOR: return subsize + 3; |
293 | 0 | case Fragment::WRAP_J: return subsize + 4; |
294 | 0 | case Fragment::THRESH: return subsize + n_subs + BuildScript(k).size(); |
295 | 0 | } |
296 | 0 | assert(false); |
297 | 0 | } |
298 | | |
299 | 0 | InputStack& InputStack::SetAvailable(Availability avail) { |
300 | 0 | available = avail; |
301 | 0 | if (avail == Availability::NO) { |
302 | 0 | stack.clear(); |
303 | 0 | size = std::numeric_limits<size_t>::max(); |
304 | 0 | has_sig = false; |
305 | 0 | malleable = false; |
306 | 0 | non_canon = false; |
307 | 0 | } |
308 | 0 | return *this; |
309 | 0 | } |
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 | 0 | InputStack& InputStack::SetMalleable(bool x) { |
322 | 0 | malleable = x; |
323 | 0 | return *this; |
324 | 0 | } |
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; |
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) { |
333 | 0 | a.SetAvailable(Availability::NO); |
334 | 0 | } else if (a.available == Availability::MAYBE || b.available == Availability::MAYBE) { |
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; |
343 | 0 | if (b.available == Availability::NO) return a; |
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; |
346 | 0 | if (!b.has_sig && a.has_sig) return b; |
347 | 0 | if (!a.has_sig && !b.has_sig) { |
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; |
354 | 0 | if (a.malleable && !b.malleable) return b; |
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) { |
359 | 0 | return std::move(a.size <= b.size ? a : b); |
360 | 0 | } else if (a.available == Availability::MAYBE && b.available == Availability::MAYBE) { |
361 | 0 | return std::move(a.size >= b.size ? a : b); |
362 | 0 | } else if (a.available == Availability::YES) { |
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) { |
374 | 0 | std::vector<unsigned char> push_data; |
375 | 0 | opcodetype opcode; |
376 | 0 | if (!script.GetOp(it, opcode, push_data)) { |
377 | 0 | return {}; |
378 | 0 | } else if (opcode >= OP_1 && opcode <= OP_16) { |
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) { |
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) { |
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) { |
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) { |
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)) { |
398 | 0 | if (!CheckMinimalPush(push_data, opcode)) return {}; |
399 | 0 | } else if (it != itend && (opcode == OP_CHECKSIG || opcode == OP_CHECKMULTISIG || opcode == OP_EQUAL || opcode == OP_NUMEQUAL) && (*it == OP_VERIFY)) { |
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) { |
411 | 0 | return 0; |
412 | 0 | } |
413 | 0 | if (!in.second.empty()) { |
414 | 0 | if (IsPushdataOp(in.first) && !CheckMinimalPush(in.second, in.first)) return {}; |
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) { |
425 | 0 | if (sp[i] == m) return i; |
426 | | // We only search within the current parentheses |
427 | 0 | if (sp[i] == ')') break; |
428 | 0 | } |
429 | 0 | return -1; |
430 | 0 | } |
431 | | |
432 | | } // namespace internal |
433 | | } // namespace miniscript |