I'm having some trouble understanding malleability in miniscript. Specifically I cannot get why some solutions can be used instead of other.
I think using an example may help.
Say, for instance, this miniscript:
and_v(v:pk(key),or_b(l:after(100),al:after(200)))
, which produces:
<key> OP_CHECKSIGVERIFY OP_IF
0
OP_ELSE
<64> OP_CHECKLOCKTIMEVERIFY
OP_ENDIF
OP_TOALTSTACK OP_IF
0
OP_ELSE
<c800> OP_CHECKLOCKTIMEVERIFY
OP_ENDIF
OP_FROMALTSTACK OP_BOOLOR
These are some witnesses that would solve the script above:
{ script: 'OP_0 OP_0 <sig(key)>', nLockTime: 200 },
{ script: 'OP_1 OP_0 <sig(key)>', nLockTime: 100 },
{ script: 'OP_0 OP_1 <sig(key)>', nLockTime: 200 }
However, the "Non-malleable satisfaction algorithm" would mark solution OP_0 OP_0 <sig(key)>
as DONTUSE
(if I'm not mistaken; see more below) and, thus, this solution should not be used.
This is because OP_0 OP_0 <sig(key)>
is produced using a branch where a non-canonical satisfaction for or_b
is used and the algorithm says:
The non-canonical options for and_b, or_b, and thresh are always overcomplete (reason 3), so instead use
DONTUSE
there
BTW, I am making the assumption that there in the quote above means that the DONTUSE
marker must set only on that particular non-canonical sat of or_b
: [sat(Z) sat(X)]
(and not to the rest of canonical siblings: dsat(Z) sat(X); sat(Z) dsat(X);
). I'm not sure about this interpretation.
That said, could you explain to me what would be the problem if OP_0 OP_0 <sig(key)>
was used instead of OP_0 OP_1 <sig(key)>
?
What advantage would it give attackers? Both are interchangeable.
Or does perhaps there mean all or_b
sats should be marked as DONTUSE
?