wizardsardine / liana

The missing safety net for your coins
https://wizardsardine.com/liana
BSD 3-Clause "New" or "Revised" License
324 stars 60 forks source link

Multi timelocked paths support #54

Closed darosior closed 1 year ago

darosior commented 2 years ago

The first version will only support one directly available path and a second, timelocked, path. We plan to add multisig support to each of these paths in the second version (#53).

In the third release of the software the user should be able to use multiple timelocked paths. For instance (throwing random ideas, haven't thought this setup through):

darosior commented 1 year ago

@edouardparis layed out some thoughts on how to move forward with this in https://github.com/revault/liana/issues/53#issuecomment-1366822552. This is my response to his comment, moved here to keep the discussion on the dedicated issue.

It's interesting how you are really speaking in terms of Miniscript "semantic policy". It's exactly what i had in mind too. But we also need to decide how restrictive we want to be:

As usual i'd be in favour of starting up with strict rules and relaxing them on a case by case basis, if the advantage clearly outweigh the software and UX complexity.

I like your suggestion for the descriptor configuration in the installer. However i think it should be part of some sort of advanced mode. By default we should probably have pre-defined templates like:

The hack you suggest of abusing the bip32_derivation PSBT field for passing information to the GUI has several issues:

  1. As a general rule we shouldn't special case the GUI as a client of the daemon. A behaviour of the daemon tailored for the GUI may be surprising to other clients, or even make it unusable for them.
  2. As a general rule, let's be explicit rather than implicit. Sure, we already rely on some PSBT information for other implicit meanings (change detection, etc..) But let's prefer being explicit where possible.
  3. It's brittle. It only ever works for the non-timelocked path. First of all the user may not know in advance what recovery path they would use at the time they create the recovery transaction. Another one may even become available by the time they sign it. Also, note that signatures for a higher sequence can be used for a lower timelock. Let me illustrate this. Think of the script "Key A immediately, key B after 10 blocks, key C after 20 blocks". It has three paths. We may create a recovery transaction with a sequence of 20 with the purpose of spending through the third path. But a signature for key B may allow us to spend through the second spending path.

Maybe instead we should create the recovery transaction with the largest possible sequence according to the current block height? And allow the user to configure it in case they plan to sign it in the future when more paths will become available?

Regarding the presentation of the thresholds on the GUI we could display the number of signatures per available path? In most cases when no recovery path is available it'll only show a single threshold (or none if it's not a multisig).

Finally, there is a discussion to be had with signing device devs: should the signing device append a signature for all paths it can when presented a PSBT? CC @bigspider (we already discussed that on Ledger's Discord iirc).

bigspider commented 1 year ago

About the signing: at this time, Ledger signs with all the keys it can (and soon: all the tapleaves); of course, you could always update the psbt with a subset of the returned signatures. However, one would have to think if this affect the security model − that is: what if the Liana client has malware? Can attackers do something bad by having the additional signature? I think the answer is yes if some cosigner keys are compromised, but it might not ba a problem for every policy, so one might want to consider the question on a case-by-case basis.

Adding some flags to specify what keys to use (for a policy with multiple internal keys) is of course possible, and not that difficult technically (although it might present some UX challenges, as the user should be aware of the selective signing on the hardware wallet screen). Note that there are probably two types of "filter" to consider:

  1. select which internal key(s) sign with (for any script type)
  2. [P2TR only]: select which leaves to sign in a taptree (plus yes/no for the key-path spend, if internal)

They could of course interact if a tapscript has multiple internal keys.

Finally: should these limitations apply per input, or per transaction? In the context we're discussing for Liana, per transaction seems the only thing that makes sense; but the fact that PSBT data is per input might complicate the filtering for the tapleaves.

Perhaps a simplification that is worth making is: only the filtering for keys is implemented (type (1) above). In the context of wallet policies, you could just specify a bitmap for the key placeholder you want to sign with. If you need to do the second type of filtering, you can always modify the policy to use different internal keys in different tapleaves. By using key placeholders instead of pubkeys for the filtering, it applies to all the inputs equally in a consistent way, so I think it's the right approach.

So while none of this is hard technically, there is certainly some complexity in the specs and UX that needs a lot more thinking.