Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help Wanted, Understanding duplicate keys in conditions #142

Closed
miketwenty1 opened this issue Sep 2, 2024 · 9 comments
Closed

Help Wanted, Understanding duplicate keys in conditions #142

miketwenty1 opened this issue Sep 2, 2024 · 9 comments

Comments

@miketwenty1
Copy link

I'm trying to build some pseudo miniscript code and check my logic with the compiler on bitcoin.sipa.be/miniscript. I'm trying to work my way outward, to a more complicated script. I'm getting stuck with this below nested example. I want to have a threshold 3/4 with timelock 1000, OR, 2/4 with 3000.

It seems the parent or directly going to and's is not the proper syntax. How would I be able to accomplish this sort of multiple or timelock conditions with miniscript?

or(
    and(
        thresh(3, pk(A), pk(B), pk(C), pk(D)),
        older(1000)
    ),
    and(
        thresh(2, pk(A), pk(B), pk(C), pk(D)),
        older(3000)
    )
)

Condensed: or(and(thresh(3, pk(A), pk(B), pk(C), pk(D)),older(1000)), and(thresh(2, pk(A), pk(B), pk(C), pk(D)),older(3000)))

Note, the individual inner and's work fine.

@sipa
Copy link
Owner

sipa commented Sep 2, 2024

I think the compiler doesn't support spaces inside policy strings. Other than that, this seems like it should work.

@sipa
Copy link
Owner

sipa commented Sep 2, 2024

I think this policy is also equivalent to and(older(1000),thresh(3,older(3000),pk(A),pk(B),pk(C),pk(D))), which will compile to something more compact as it won't need to emit the pk() checks twice each (the compiler currently cannot deduplicate subexpressions).

@sipa
Copy link
Owner

sipa commented Sep 2, 2024

Oh, the compilation error is due to key reuse within the policy; miniscript's non-malleability properties rely on keys not being reused (i should add an option to the site to ignore this, probably).

@miketwenty1
Copy link
Author

miketwenty1 commented Sep 2, 2024

I noticed the miniscript implementation in rust throws PolicyError(DuplicatePubKeys). So matches with what you're saying.
For clarity, if A, (Alice) was in 3 logic branches the better idea would be she provide 3 separate keys? All these keys could come from the same xpriv?

I'm not really understanding how malleability comes into play here. The keys needing to sign would not change, is this in the case for utxo spending?

Also in ref to what you offered:

and(
    older(1000),
    thresh(
        3,
        older(3000),
        pk(A),
        pk(B),
        pk(C),
        pk(D)
    )
)

I didn't know you could have a timelock in the thresh, this is very cool!

@miketwenty1 miketwenty1 changed the title Help Wanted, Understanding nested conditions Help Wanted, Understanding duplicate keys in conditions Sep 2, 2024
@bigspider
Copy link

bigspider commented Sep 2, 2024

I noticed the miniscript implementation in rust throws PolicyError(DuplicatePubKeys). So matches with what you're saying. For clarity, if A, (Alice) was in 3 logic branches the better idea would be she provide 3 separate keys? All these keys could come from the same xpriv?

For wallet accounts, the standard that wallets like Liana are using (kinda implied by BIP-388's placeholders) is to have A/<0;1>/*, A/<2;3>/* and A/<4;5>/* for the three branches. This guarantees that no pubkey is ever reused not only within the same UTXO (which causes malleability issues in miniscript), but also across different UTXOs of the same logical 'account' (that is a privacy issue) - as long as one doesn't reuse addresses, of course.

@miketwenty1
Copy link
Author

@bigspider AFAIU only 1 spending path can ever be put on chain to satisfy a tapscript? So why is this considered a malleability issue, if there's redundant usage of a key in logic branches that are there as backup conditions?

@bigspider
Copy link

@bigspider AFAIU only 1 spending path can ever be put on chain to satisfy a tapscript? So why is this considered a malleability issue, if there's redundant usage of a key in logic branches that are there as backup conditions?

Miniscript's malleability issues are about a single Script, so either:

  • on Segwit (you'd have a single large Script with all the alternative ways of spending);
  • within a single tapscript (less common, but you can have multiple spending conditions in the same tapleaf).

On taproot, you can technically use the same pubkey across different leaves, and in most cases it would be perfectly fine, as you said.

(Off-topic, but: BIP-388 forbids reusing the exact same pubkey even across different leaves. However, that was a choice mostly for practical convenience and some considerations about future-proofing, not related to malleability)

@miketwenty1
Copy link
Author

miketwenty1 commented Sep 2, 2024

I'm still a little confused on what an example condition woud be to cause malleability, but I get there's an idea of a complexity/genericity tradeoff miniscript made here with key reuse to address it. thanks.

@bigspider
Copy link

I'm still a little confused on what an example condition woud be to cause malleability, but I get there's an idea of a complexity/genericity tradeoff miniscript made here with key reuse to address it. thanks.

@darosior wrote a nice general explainer: https://bitcoin.stackexchange.com/a/116282/101498

Pubkey reuse causes malleability because the same signature works for multiple spending conditions.

For example if you have a miniscript like or_i(pk(A),pk(A)), then <sig A> <> or <sig A> <1> are both valid, and the point is that anyone who sees either, can produce the other one - not just Alice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants