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

Add plugin hook for penalty transactions on revocation #3422

Closed
3 tasks done
cdecker opened this issue Jan 20, 2020 · 10 comments · Fixed by #3659
Closed
3 tasks done

Add plugin hook for penalty transactions on revocation #3422

cdecker opened this issue Jan 20, 2020 · 10 comments · Fixed by #3659

Comments

@cdecker
Copy link
Member

cdecker commented Jan 20, 2020

There are a number of designs for watchtowers based on encrypting the penalty
transaction and shipping it to a semi-trusted third-party. In order to
facilitate the implementation of watchtowers it'd be good to generate penalty
transactions for each commitment upon receiving the revocation and deliver it
to a plugin that takes care of the communication with the actual
watchtower. We'd do so without encrypting the information, however we'd give
the plugin enough information to perform the encryption itself. This maximizes
the flexibility of the watchtower scheme, and even allows for self-hosted
watchtowers that do not require encryption at all. For example it is possible
to run a personal watchtower node at home and a mobile wallet that just pushes
penalty transactions to the personal watchtower.

The main difficulty is in generating the penalty transaction, since that is
currently done only in onchaind, and we'd need to generate them for each
commitment, either in lightnignd or channeld now.

Plugin interface

A hook is likely the best option since it allows us to synchronously call the
watchtower plugin which can make sure the bundle has been delivered at
whatever watchtower backend it is talking to before allowing lightningd to
continue running. A notification on the other hand could lead to a bundle
being dropped, which could lead to a cheat attempt for which the watchtower
doesn't have a matching penalty.

The hook payload would consist of the following fields:

{
	"tx": "[serialized and fully signed penalty tx",
	"commitment_txid": "[commitment tx this penalizes]",
	"to_self_delay": 1234
}

Steps

  • Extract penalty transaction generation into common/
  • Generate penalty transactions
  • Implement the hook call with the newly generated information
@ZmnSCPxj
Copy link
Collaborator

not require encryption at all. For example it is possible
to run a personal watchtower node at home and a mobile wallet that just pushes
penalty transactions to the personal watchtower.

Pedantic: Still needs an encrypted channel between the mobile wallet and the home device, so ---

Otherwise looks OK.

@sr-gi
Copy link
Contributor

sr-gi commented Jan 21, 2020

This looks great from our side. Thanks for making the effort to ease the interaction with watchtowers 😄

@cdecker
Copy link
Member Author

cdecker commented Jan 21, 2020

not require encryption at all. For example it is possible
to run a personal watchtower node at home and a mobile wallet that just pushes
penalty transactions to the personal watchtower.

Pedantic: Still needs an encrypted channel between the mobile wallet and the home device, so ---

Otherwise looks OK.

Right, I was mainly concerned about the payload, and less about transport. Will rephrase in OP 👍

@sr-gi
Copy link
Contributor

sr-gi commented Feb 19, 2020

A question regarding the hook and signmessage rpc:

Are you planning on allowing signmessage to work with ephemeral keys (instead of only with the node private key)?

In the new iteration of BOLT13 we'll be proposing user authentication with the tower via signed messages, that, tentatively, could be done using the node private key or an ephemeral key.

We were thinking on using the same approach as signmessage / verifymessage (h/t @cdecker) so it comes out of the box with nodes.

There are a couple of caveats we can foresee with this though (and therefore my question):

@ZmnSCPxj
Copy link
Collaborator

ZmnSCPxj commented Mar 3, 2020

@sr-gi If the key is ephemeral, presumably you generated it from some randomly-selected privkey, in which case you can just use libsecp256k1 directly or in one of the many language-specific wrappers.

Why does the watchtower need a signature created by anybody else? I suggest using blinded bearer signatures, either the original RSA ones or the nice new EC ones from privacypas. That way the watchtower only sees its own signatures (which it generated via blind-signing), and the node can keep its anonymity. I.e. the watchtower operates as a Chaumian bank, issues tokens (i.e. leases on the watchtower service) in exchange for money (or even just somebody begging free tokens if you want to make your watchtower a free service), then later when somebody claims a token, provides the service that it promised to offer in exchange for the token. The tokens are blinded signatures. Have the node contact the watchtower over a new Tor circuit on each sending of watching data (i.e. NEWNYM after every use), and the watchtower is unable to usefully correlate watchtower blobs to nodes.

@ZmnSCPxj
Copy link
Collaborator

ZmnSCPxj commented Mar 3, 2020

@cdecker how about exposing the commitment_tx as well as its txid?

One possibility for a low-overhead watchtower would be for the watchtower to be SPV. Most SPV interfaces are designed to look for transactions that pay to/from a specific address/scriptPubKey (Electrum, Neutrino). So instead of monitoring for a specific commitment transaction ID appearing onchain, the watchtower monitors a specific address that appears on obsolete commitment transactions. If that address is paid to onchain, then it is likely that the obsolete commitment transaction was published.

So what could be done would be:

  • Get any output address/scriptPubKey of the obsolete commitment transaction.
  • AEAD-encrypt the penalty transaction with the commtiment transaction ID as the AEAD encryption key.
    • Or just AE, what additional data do you need anyway...?
  • Send the address plus the encrypted blob to the watchtower.

The resulting address plus encrypted blob does not leak information to the watchtower: all commitment tx output addresses are generated directly or indirectly using per_commitment_point, which is known only by the counterparties in the channel, and which the watchtower can only guess at.

Then, when the address is found onchain or on mempool, the watchtower can find the txid of the transaction that actually pays to that address (using normal Electrum/Neutrino queries), and tries to AEAD-decrypt the encrypted blob using the transaction ID as the key. If decryption fails then the transaction that paid to that address is not the commitment transaction. If decryption succeeds then the watchtower is now in possession of the penalty transaction.

The above scheme requires that the commitment_tx, not just commitment_txid, be provided to the plugin that communicates with the watchtower.

@sr-gi
Copy link
Contributor

sr-gi commented Mar 3, 2020

@ZmnSCPxj I discussed this with Christian and Rusty and completely forgot to get back here to comment.

We were thinking on something similar, by using tweaks over the node private key. The main reasons why we where thinking on this over blinded tokens was to:

  • Reduce the amount of data the node needs to keep around in order to use the tower.
  • Allow the user to update/delete appointments.
  • Perform bulk deletion.

With the tweak approach the user should be able to only keep around a tweak:tower_id pair.

Regarding update/deletion, the user may need to update some of the appointments for ones with higher fees, specially in the short future since no CPFP approach has been set for penalty transactions. On the other hand, appointment deletion once the channel is closed should be an option so space can be freed.

Finally, bulk deletion can be performed if appointments from the same channel are linked on the tower side. This can be achieved, in a privacy preserving way, by using tabs. By adding a tab_id derived from the channel_id (e.g. sha256(magic_number|channel_id)) the tower can group all the updates in the same tab, and delete all of them after a breach or upon request when a channel is closed.

We're also thinking on the Tor approach to establish the connection between the user and the tower, since otherwise the tower will know the node_id and the tweak will provide no privacy.

EDIT:

Thinking this trough though all of it should be possible with blinded tokens instead of signatures, as long as the token can be reused over a time period. It seems a bit overkill though, what are the benefits you see on it over a signing + EC recover?

@ZmnSCPxj
Copy link
Collaborator

ZmnSCPxj commented Mar 4, 2020

It would require exposing an API at lightningd to be able to sign a message using a derived key. Further, if you are using a derived key, if you do not use hardened derivation, it is theoretically possible to reverse the parent pubkey from the child pubkey, thus still letting the watchtower learn which node it was talking to. If you use hardened derivation you cannot tweak using the existing signmessage (and I am uncertain if even with unhardened derivation you can still tweak with the existing signmessage, does it somehow commit the pubkey it is signing with on the message? will have to dig...). This API goes all the way to the hsmd as well, which adds even more complication to an eventual hardware signer for lightningd. Though since no hardware currently exists, we still have some leeway to actually change the hsmd API as well, so there is that; presumably hardened derivation is not so hard to add to a hardware module.

I mildly prefer keeping the hsmd API as frozen as possible; the software can afford to keep more data, in a world with gigs of hard disk space, whereas bespoke hardware like a true HSM would have to be more limited in abilities (and ideally, would not require any firmware updates at all, as that reintroduces issues with software updates; this requires perfection in the HSM design and implementation, which is easier if the HSM is simpler and has less it needs to expose).

as long as the token can be reused over a time period

Bearer tokens, if intercepted, can then be used by third parties who have acquired a copy of the token. They are equivalent to a symmetric key; you only get good security properties if it is a one-time password. You could try to get around this by using an encrypted tunnel with the watchtower, or by using a challenge-response protocol somehow (which might not exist for the bearer token you might want to use).

This can be achieved, in a privacy preserving way, by using tabs.

This still correlates all activity on a channel, which in combination with other metadata may still allow a tower (or anyone who hacks it) to figure out which channel it is and then leak all the timings of that channel with 100% accuracy. For example, a hacker who gets read access to the tower data can try routing through a channel it suspects is protected by the tower; if it is able to identify that a tab correlates with a specific channel, it now can get a hint on the previous history of that channel, by looking at the entries that have the same tab.

What you could do would be to use this novel cryptographic construct I invented, the recognition code ("Recognition code 927, I am a potato"). This is nothing more than having a secret scalar, and signing that scalar with itself (i.e. it is both the message that is hashed and signed, and the signing key), with the resulting signature as the recognition code. If you know the secret scalar, you can recognize the recognition code by checking if it is a valid signature for the secret scalar times G, with the message as the hash of the secret scalar. The intent is not to prove to third parties that you signed; it is to prove to yourself that you signed, in case you forgot something. If you use an apparently-random R at each recognition code, then no third party can correlate a set of recognition codes as belonging to a specific scalar, except yourself; third parties cannot EC recover since that would require knowledge of the message (which in this case is the secret key, which you obviously keep secret and not send with the recognition code); and third parties cannot forge recognition codes without knowledge of the secret scalar. So instead of exposing a tab to the tower, you use the tab to derive a secret scalar behind a set of recognition codes: each channel update you send to the tower has a fresh recognition code (with a fresh R) from the tab. On channel closure, you ask the tower for all the recognition codes, then filter them on which matches the tab of the closed channel (which you can recognize as only you know the tab). You can mislead the tower by not deleting the entries with matching recognition codes at once; you could wait for another channel to close, for example, and mix the to-be-deleted entries of those channels together; etc. Hackers who can read the tower data can still correlate a channel as being protected by that tower via timing+probe attacks, but would at least not be able to get history data, since it would not be able to match the channel ID (magic_number is secret, right? I assumed it is, but you did not specify...) to the recognition codes.

@sr-gi
Copy link
Contributor

sr-gi commented Mar 4, 2020

It would require exposing an API at lightningd to be able to sign a message using a derived key. Further, if you are using a derived key, if you do not use hardened derivation, it is theoretically possible to reverse the parent pubkey from the child pubkey, thus still letting the watchtower learn which node it was talking to. If you use hardened derivation you cannot tweak using the existing signmessage (and I am uncertain if even with unhardened derivation you can still tweak with the existing signmessage, does it somehow commit the pubkey it is signing with on the message? will have to dig...). This API goes all the way to the hsmd as well, which adds even more complication to an eventual hardware signer for lightningd. Though since no hardware currently exists, we still have some leeway to actually change the hsmd API as well, so there is that; presumably hardened derivation is not so hard to add to a hardware module.

Would it make any difference if it's an ephemeral key instead of a derived key? The goal of making it derived was to reduce the overhead, but having a different set of keys to use with towers will also do.

Bearer tokens, if intercepted, can then be used by third parties who have acquired a copy of the token. They are equivalent to a symmetric key; you only get good security properties if it is a one-time password. You could try to get around this by using an encrypted tunnel with the watchtower, or by using a challenge-response protocol somehow (which might not exist for the bearer token you might want to use).

The issue with this is that if you cannot identify request from the same user you cannot even give a service beyond storing data. Updates, deletion and requests (to prove that the data is being kept on the tower side for instance) should only be allowed to the user who sent the data, otherwise we'd open the door to many type of attacks on the tower. This seems to complicate the protocol quite a bit IMHO.

This still correlates all activity on a channel, which in combination with other metadata may still allow a tower (or anyone who hacks it) to figure out which channel it is and then leak all the timings of that channel with 100% accuracy. For example, a hacker who gets read access to the tower data can try routing through a channel it suspects is protected by the tower; if it is able to identify that a tab correlates with a specific channel, it now can get a hint on the previous history of that channel, by looking at the entries that have the same tab.

True, but this should be similar to what a routing node connected to the target is already getting, at an arguably lower cost. A routing node having a channel with the victim with enough liquidity and no fees may be getting all payments not going to direct channels of the target, the total amount going out of the target (which defines a higher bound on the payment amount) and even knowing which of them fail or not. A tower following the tab approach only knows the amount of traffic that is routed trough a blinded channel.

Anyway, the tab approach is something optional that reduces the interaction between the user and the tower if the user decides to opt-in. Otherwise the user can always choose random tab_ids for every update so they cannot be correlated.

@ZmnSCPxj
Copy link
Collaborator

ZmnSCPxj commented Mar 5, 2020

Would it make any difference if it's an ephemeral key instead of a derived key? The goal of making it derived was to reduce the overhead, but having a different set of keys to use with towers will also do.

Then you would not need to request lightningd to sign anything (i.e. the plugin holds its own keys), which is helpful.

You could have the plugin hold its own key.

The issue with this is that if you cannot identify request from the same user you cannot even give a service beyond storing data. Updates, deletion and requests (to prove that the data is being kept on the tower side for instance) should only be allowed to the user who sent the data, otherwise we'd open the door to many type of attacks on the tower. This seems to complicate the protocol quite a bit IMHO.

Then use the token to register a lifetime of one watched transaction: insert-delete of a single registered commitment transaction. At insertion you present the token and a (hash of a) pubkey. At deletion you present a signature with that pubkey. In between insertion and deletion, if the specified commitment transaction appears, the watchtower can auto-delete the entry by itself.

When the client opens a channel, and then the channel is updated (and the old commitment tx is revoked) the client gets an unused token and registers the old commitment tx plus a pubkey it can derive from its client privkey plus the commitmentt tx. At each update it does the same: get an unused token (possibly paying to the watchtower for new tokens if it runs low on tokens) and registers it with a pubkey derived from its privkey plus commitment tx. Once the channel is closed, it deletes all the registered old commitments.

True, but this should be similar to what a routing node connected to the target is already getting, at an arguably lower cost.

You are thinking in single channels. But a node using a watchtower is likely to use the same watchtower on all channels (unless you are proposing to only use one channel per watchtower). The peer gets the same inforrmation, but only for the very specific channel the target node has with it. On the other hand, a hacker getting read-only access to the watchtower you are using can now probe every channel you have once, learn the tab of each channel, and from there know the history of every update you have on every channel you have, which is more than what a single peer can get. This approaches someone successfully eclipsing your node and monitoring your every interaction. From this information the read-only hacker can have a good idea of what payments you made yourself, and what payments you are forwarding from others: if tab0 gets an update and a few milliseconds later tab1 gets an update, that is likely a forward, while if tab2 gets an update but nothing else triggers in a short while, it is likely a send or receive terminating at you. The channel that tab2 has gives it a hint as to who you were transacting with (in general, the channel is probably on the shortest path between you and whoever you were transacting with). And so on. With no consistent tab per channel, that information is not recoverable by a read-only hacker.

I mean --- even small leaks are big leaks when correlated with other data. So you make an effort to reduce the amount of data you can leak each time.

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