revault / practical-revault

Version 0 specifications for a Revault deployment
Creative Commons Attribution 4.0 International
33 stars 9 forks source link

Prevent ANYONECANPAY-signed inputs replay #83

Open darosior opened 3 years ago

darosior commented 3 years ago

In order for watchtowers to be able to fee-bump Cancel and Emergencies transactions and to get around transactions pining, stakeholders exchange ANYONECANPAY | ALL signatures.

It was known that the malleability introduced could cause some issues, however they were minors and mostly considered in the realm of fee bumping (eg stripping the fee bumping input). Now, some design decisions make it actually practical to DOS the operation by merging Cancel or Emergencies transactions together (effectively burning an entire input to fees) under certain conditions.

Consider the Cancel transaction. Two deposit transactions paying to the same address for the same amount will create a transaction chain ultimately paying to the Cancel output (same address and amount, as we reuse keys across the transaction chain and have static fees). The ACP | ALL will not (as would a ACP | SINGLE) commit to the input index used, it can therefore be freely placed as second, third, or whatever input in a transaction given that this transaction contains a single output to the Cancel utxo. Thus, the signature would be valid as a second input of a second transaction. It would effectively result in burning an entire vault.

Therefore we need a way to commit to a specifc Unvault txo (or Deposit for an Emergency) per transaction or to the index in the transaction. There are many ways to do so:

darosior commented 3 years ago

Hmm so i'm now really hesitating with tweaking the public keys à la BIP32 or Lightning Network with the tweak being the unvault outpoint, it'd be a huge win... At the expense of surely making coin tracking more complicated.

darosior commented 3 years ago

We could also "just" change the Cancel descriptor from

wsh(thresh(4, stk_a, stk_b, stk_c, stk_d))

To

wsh(thresh(5, stk_a, stk_b, stk_c, stk_d, hash160(H)))

With H = hash160(unvault_txid | unvault_vout). Probably better to go this way at the expense of ~83 witness units for not playing the cryptographers with no real idea of what we are doing.

JSwambo commented 3 years ago

Is there any chance that the Unvault Tx will batch deposit UTxOs in a future version? If so should we consider committing to the vout too in the Cancel and Unvault-Emergency Txs now?

What about the Spend Tx? Are they always signed with ALL?

darosior commented 3 years ago

To be honest i don't think we should do this for the Cancel, but rather https://github.com/revault/practical-revault/pull/83#issuecomment-812465918 .

What about the Spend Tx? Are they always signed with ALL?

Yes. I mean it's left to the managers, they could sign with NONE if they want, but they could also leak their keys.

JSwambo commented 3 years ago

Maybe I'm wrong, but it seems like there is nothing stopping an attacker from choosing H to be the same when constructing both Cancel Tx 1 and Cancel Tx 2. What verification do we have that the H are unique? What verification is there that the H actually has committed to the correct previous Unvault Txid? Do we expect the stakeholders to verify this on the HW screen? How do they know what to compare with?

darosior commented 3 years ago

What verification do we have that the H are unique?

They would not exchange signatures for the same transaction. Say A, B, C are stakeholders and C is trying to sneak an invalid commitment to the Unvault txid (or outpoint for that matter). A and B would verify C's signature against their own transaction (with the right commitment) which would raise an error.

Now, for the enforcement of the verification.. I wonder if it's possible to do on the HW and asked @stepansnigirev by mail some time ago. It seems possible since it's an information internal to the transaction, but i would have to implement it to really be sure of what it takes.

FWIW this solution would:

JSwambo commented 3 years ago

What verification do we have that the H are unique?

They would not exchange signatures for the same transaction.

Right, so we assume at least 1 of the stakeholders' wallets is not compromised. Notably, this has nothing to do with their HW, unless we have some HW feature that reliably let's stakeholders check the H is consistent with the associated unvault Tx.

It seems possible since it's an information internal to the transaction, but i would have to implement it to really be sure of what it takes.

Well, isn't it information internal to the previous Tx?

darosior commented 3 years ago

we assume at least 1 of the stakeholders' wallets is not compromised

One of their HW* if it can be generated by the HW. If you are the last honest stakeholder standing, your HW won't send rogue signatures to the other participants.

Also, there is the brittle argument of the watchtower ACK that may one day be checked on the HW.

Well, isn't it information internal to the previous Tx?

Your transaction refers the outpoints it spends, therefore it's part of your transaction's input.

JSwambo commented 3 years ago

we assume at least 1 of the stakeholders' wallets is not compromised

if it can be generated by the HW.

That's what I was getting at with ....

unless we have some HW feature that reliably let's stakeholders check the H is consistent with the associated unvault Tx.

If that feature is robust, then the assumption becomes 'at least one of the stakeholders' HW is not compromised'.

Your transaction refers the outpoints it spends, therefore it's part of your transaction's input.

ah yeah of course!

JSwambo commented 3 years ago

Also, there is the brittle argument of the watchtower ACK that may one day be checked on the HW.

Are you suggesting the WT could refuse to ACK if it notices the inconsistency (H incorrect)?

darosior commented 3 years ago

That's what I was getting at with ....

Yes but the premise is wrong, they don't need to verify it but to trust the HW (they don't re-compute the signature by hand each time they sign, they just assume that the HW does its job right).

Are you suggesting the WT could refuse to ACK if it notices the inconsistency (H incorrect)?

Well watchtowers do verify signatures before ACKing

JSwambo commented 3 years ago

Yes but the premise is wrong, they don't need to verify it but to trust the HW

Ok. If the check is fully automated, then the trust is on the HW software. That's much better in terms of UX. Is this in the revault-compatibility HW features list somewhere?

darosior commented 3 years ago

Is this in the revault-compatibility HW features list somewhere?

https://github.com/revault/practical-revault/pull/83#issuecomment-829274349 :

I wonder if it's possible to do on the HW and asked stepansnigirev by mail some time ago.

darosior commented 3 years ago

My last approach is clearly not going to work for HWs (they can't bear storing an infinite amount of descriptors..). I'm now thinking of stuffing a short-channel-id in nLockTime and nSequence à la Lightning. The issue is that we only have 6 bytes available where we need 8 of them for the scid (and arguably even 9)..