| 1245 | |
| 1246 | template<typename Ctx> |
| 1247 | internal::InputResult ProduceInput(const Ctx& ctx) const { |
| 1248 | using namespace internal; |
| 1249 | |
| 1250 | // Internal function which is invoked for every tree node, constructing satisfaction/dissatisfactions |
| 1251 | // given those of its subnodes. |
| 1252 | auto helper = [&ctx](const Node& node, std::span<InputResult> subres) -> InputResult { |
| 1253 | switch (node.fragment) { |
| 1254 | case Fragment::PK_K: { |
| 1255 | std::vector<unsigned char> sig; |
| 1256 | Availability avail = ctx.Sign(node.keys[0], sig); |
| 1257 | return {ZERO, InputStack(std::move(sig)).SetWithSig().SetAvailable(avail)}; |
| 1258 | } |
| 1259 | case Fragment::PK_H: { |
| 1260 | std::vector<unsigned char> key = ctx.ToPKBytes(node.keys[0]), sig; |
| 1261 | Availability avail = ctx.Sign(node.keys[0], sig); |
| 1262 | return {ZERO + InputStack(key), (InputStack(std::move(sig)).SetWithSig() + InputStack(key)).SetAvailable(avail)}; |
| 1263 | } |
| 1264 | case Fragment::MULTI_A: { |
| 1265 | // sats[j] represents the best stack containing j valid signatures (out of the first i keys). |
| 1266 | // In the loop below, these stacks are built up using a dynamic programming approach. |
| 1267 | std::vector<InputStack> sats = Vector(EMPTY); |
| 1268 | for (size_t i = 0; i < node.keys.size(); ++i) { |
| 1269 | // Get the signature for the i'th key in reverse order (the signature for the first key needs to |
| 1270 | // be at the top of the stack, contrary to CHECKMULTISIG's satisfaction). |
| 1271 | std::vector<unsigned char> sig; |
| 1272 | Availability avail = ctx.Sign(node.keys[node.keys.size() - 1 - i], sig); |
| 1273 | // Compute signature stack for just this key. |
| 1274 | auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail); |
| 1275 | // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further |
| 1276 | // next_sats[j] are equal to either the existing sats[j] + ZERO, or sats[j-1] plus a signature |
| 1277 | // for the current (i'th) key. The very last element needs all signatures filled. |
| 1278 | std::vector<InputStack> next_sats; |
| 1279 | next_sats.push_back(sats[0] + ZERO); |
| 1280 | for (size_t j = 1; j < sats.size(); ++j) next_sats.push_back((sats[j] + ZERO) | (std::move(sats[j - 1]) + sat)); |
| 1281 | next_sats.push_back(std::move(sats[sats.size() - 1]) + std::move(sat)); |
| 1282 | // Switch over. |
| 1283 | sats = std::move(next_sats); |
| 1284 | } |
| 1285 | // The dissatisfaction consists of as many empty vectors as there are keys, which is the same as |
| 1286 | // satisfying 0 keys. |
| 1287 | auto& nsat{sats[0]}; |
| 1288 | CHECK_NONFATAL(node.k != 0); |
| 1289 | assert(node.k < sats.size()); |
| 1290 | return {std::move(nsat), std::move(sats[node.k])}; |
| 1291 | } |
| 1292 | case Fragment::MULTI: { |
| 1293 | // sats[j] represents the best stack containing j valid signatures (out of the first i keys). |
| 1294 | // In the loop below, these stacks are built up using a dynamic programming approach. |
| 1295 | // sats[0] starts off being {0}, due to the CHECKMULTISIG bug that pops off one element too many. |
| 1296 | std::vector<InputStack> sats = Vector(ZERO); |
| 1297 | for (size_t i = 0; i < node.keys.size(); ++i) { |
| 1298 | std::vector<unsigned char> sig; |
| 1299 | Availability avail = ctx.Sign(node.keys[i], sig); |
| 1300 | // Compute signature stack for just the i'th key. |
| 1301 | auto sat = InputStack(std::move(sig)).SetWithSig().SetAvailable(avail); |
| 1302 | // Compute the next sats vector: next_sats[0] is a copy of sats[0] (no signatures). All further |
| 1303 | // next_sats[j] are equal to either the existing sats[j], or sats[j-1] plus a signature for the |
| 1304 | // current (i'th) key. The very last element needs all signatures filled. |
nothing calls this directly
no test coverage detected