Skip to content

Commit 22c5b00

Browse files
darosiorsipa
andcommitted
miniscript: satisfaction support
This introduces the logic to "sign for" a Miniscript. Co-Authored-By: Pieter Wuille <[email protected]>
1 parent d0b1f61 commit 22c5b00

File tree

3 files changed

+598
-2
lines changed

3 files changed

+598
-2
lines changed

src/script/miniscript.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,76 @@ size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_
279279
assert(false);
280280
}
281281

282+
InputStack& InputStack::SetAvailable(Availability avail) {
283+
available = avail;
284+
if (avail == Availability::NO) {
285+
stack.clear();
286+
size = std::numeric_limits<size_t>::max();
287+
has_sig = false;
288+
malleable = false;
289+
non_canon = false;
290+
}
291+
return *this;
292+
}
293+
294+
InputStack& InputStack::SetWithSig() {
295+
has_sig = true;
296+
return *this;
297+
}
298+
299+
InputStack& InputStack::SetNonCanon() {
300+
non_canon = true;
301+
return *this;
302+
}
303+
304+
InputStack& InputStack::SetMalleable(bool x) {
305+
malleable = x;
306+
return *this;
307+
}
308+
309+
InputStack operator+(InputStack a, InputStack b) {
310+
a.stack = Cat(std::move(a.stack), std::move(b.stack));
311+
if (a.available != Availability::NO && b.available != Availability::NO) a.size += b.size;
312+
a.has_sig |= b.has_sig;
313+
a.malleable |= b.malleable;
314+
a.non_canon |= b.non_canon;
315+
if (a.available == Availability::NO || b.available == Availability::NO) {
316+
a.SetAvailable(Availability::NO);
317+
} else if (a.available == Availability::MAYBE || b.available == Availability::MAYBE) {
318+
a.SetAvailable(Availability::MAYBE);
319+
}
320+
return a;
321+
}
322+
323+
InputStack operator|(InputStack a, InputStack b) {
324+
// If only one is invalid, pick the other one. If both are invalid, pick an arbitrary one.
325+
if (a.available == Availability::NO) return b;
326+
if (b.available == Availability::NO) return a;
327+
// If only one of the solutions has a signature, we must pick the other one.
328+
if (!a.has_sig && b.has_sig) return a;
329+
if (!b.has_sig && a.has_sig) return b;
330+
if (!a.has_sig && !b.has_sig) {
331+
// If neither solution requires a signature, the result is inevitably malleable.
332+
a.malleable = true;
333+
b.malleable = true;
334+
} else {
335+
// If both options require a signature, prefer the non-malleable one.
336+
if (b.malleable && !a.malleable) return a;
337+
if (a.malleable && !b.malleable) return b;
338+
}
339+
// Between two malleable or two non-malleable solutions, pick the smaller one between
340+
// YESes, and the bigger ones between MAYBEs. Prefer YES over MAYBE.
341+
if (a.available == Availability::YES && b.available == Availability::YES) {
342+
return std::move(a.size <= b.size ? a : b);
343+
} else if (a.available == Availability::MAYBE && b.available == Availability::MAYBE) {
344+
return std::move(a.size >= b.size ? a : b);
345+
} else if (a.available == Availability::YES) {
346+
return a;
347+
} else {
348+
return b;
349+
}
350+
}
351+
282352
std::optional<std::vector<Opcode>> DecomposeScript(const CScript& script)
283353
{
284354
std::vector<Opcode> out;

0 commit comments

Comments
 (0)