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
DONTUSEthere
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?