Decoupling the whisper key from the wallet key

We’ve been talking about this for a long time, and now we are finally opening a new Idea to do it.

For security and privacy reasons, we want to decouple the whisper key from the wallet key, so that users don’t expose their Ethereum address while chatting in one-to-one and public chats.

It’s still a work in progress PR but I would like to open a discussion here so that everyone can join and give their ideas and opinions.

Things to think about:

1 - A new key can be derived from the HD wallet to be used for the whisper identity. For the wallet we are using the BIP44 derivation path of the first accoun/wallet (m/44'/60'/0'/0/0). Which derivation path should we use for the whisper identity?

2 - I would propose to extend the current key store to have a new field for this key, is there any risk in doing that? (we already added a new key on that, the one derived at m/44'/60'/0'/0/1. it was initially added as a parent to derive sub-accounts, but it’s never been used. code: https://github.com/status-im/status-go/blob/develop/vendor/github.com/ethereum/go-ethereum/accounts/keystore/key.go#L51, and https://github.com/status-im/status-go/blob/develop/vendor/github.com/ethereum/go-ethereum/accounts/keystore/key.go#L153)

3 - compatibility

3a- after the upgrade, the wallet address will be the same. The contact/chat address will be different, so users will need to exchange again the contacts to be able to interact.

3b - We will need a change in the protocol so that user A can request the address to user B before sending a transaction.

3c - Client A is using the old/current app, and client B is using the new version; A can send a transaction via chat to B, but that would be sent to the address derived from B’s contact code (whisper public key).B won’t see the transaction in its wallet, since with the upgrade it’s a different key.

I hope a lot of people can join and help. There will be a lot of work in all the fields, security, status-go, status-react, UX/UI, design, etc…

2 Likes

Would there be any advantage of not using a root key ever in public? I am thinking of some constants that would be used to derive keys with a particular function, for example:

  • m/44'/60'/0'/0/1 – used as a wallet address,
  • m/44'/60'/0'/0/2 – used as a Whisper key pair,
  • m/44'/60'/0'/0/N – used to interact with DApp N.

The last part can be tricky, but we don’t need to implement it in the first iteration. Also, it can be decided by the user if she/he wants to use a new key or a default one (m/44'/60'/0'/0/1) to access a given DApp.

@adam we are already using m/44'/60'/0'/0/0 for the current wallet key, and in general m/44'/60'/0'/0/[0..n], as described in BIP44, is the list of wallets/addresses that an account can have. For example, if you use metamask the default account that you see when you install the extension, is the one derived at m/44'/60'/0'/0/0. If you create another account in metamask, the second one would be m/44'/60'/0'/0/1, and then m/44'/60'/0'/0/2, and so on.
For now Status doesn’t support more multiple wallets per account, but I’m sure we will implement it in the future.

Would there be any advantage of not using a root key ever in public?

do you mean the master key m?

do you mean the master key m?

Yeah, sorry I mixed stuff. Of course, there is a huge advantage of not using the master key (m) and m/44'/60'/0'/0/0 is the first derived address we use.

I read once again your proposal and I think it’s very good.

For now Status doesn’t support more multiple wallets per account, but I’m sure we will implement it in the future.

Right and I started wondering whether we’d like to go even further and use a different address for each DApp (unless the user allows the main wallet address to be used for a given DApp). How would we do that? We can reserve m/44'/60'/0'/0/100..N addresses for DApps but it does not seem like a good and scalable solution.

@adam the second part of the derivation path (44), is the purpose defined in BIP43, which in this case is 44 based on BIP44 Multi-Account Hierarchy for Deterministic Wallets.
What about having another purpose XYZ so that we can have the same structure but completely separated with a different purpose?

We can reserve m/44’/60’/0’/0/100…N addresses for DApps but it does not seem like a good and scalable solution

This is another interesting topic! We could also here use another purpose and a deterministic path based on the hash of the dapp hostname like we said here. So that the wallet associated to a dapp is always the same.

Possibly off-topic, but I’ve seen comments about compressing the key to have better UX.

Is that worth considering too? Are there any trade-offs with a shorter key?

@Chad the compression of the key can be done anyway if we want, both if we decouple the keys or not. It would be only a different way to visualise they public key, and then the client will uncompress it and use the “original” format.

Just commenting on Compatibility.

In order not to break it in consecutive releases, we could do something as follow:

  1. In release x we create the new chat key, we listen for messages on that and the previous one, and we start propagating a change-address message that contains the new address signed by the old key, so the user can start upgrading the contact. We still publish to the old address of the contacts.
  2. In release x + 1 we start publishing on the new address of the contacts, we still listen for messages on the old address.
  3. We stop listening to the old address

That way we should not break chat compatibility, and should give us enough time for updating all the contacts.

To avoid 3c we can push out a version with the “request wallet” feature first ( without changing the key yet), so that once we change the key this scenario will not happen (unless a user is running an old version of the app, but we only support non-breaking changes on consecutive upgrades)

2 Likes

@gravityblast just clarifying. If a user wants to send ether to a whisper contact (assuming whisper key is decoupled from wallet key) will they then receive or be able to view the wallet public key and then inspect on etherscan the token holding of the whisper contact?

@Graeme Yes, after this change, user A needs to send a wallet address request to user B. User B can accepts or not. If user B accepts, user A is now able to send value to B’s address and also see all the transactions related to that address.

Thanks @gravityblast, so a UX impact of decoupling would be to design a wallet request interaction between users.

from a usability standpoint, having a sep address for each dapp means that you’re drastically spreading out funds into multiple accounts. This would introduce the need to seed addresses with funds, which opens a lot of transactions (or automated seeding which could have an expanded attack surface).

from a usability standpoint, having a sep address for each dapp means that you’re drastically spreading out funds into multiple accounts

@petty yes it’s true! with this change I would like to decouple only whisper and wallet keys, without changing anything related to dapps, but there’s also this topic about that:

In terms of decoupling whisper and wallet keys only. The first thing that comes to mind is overlap with other wallet’s behavior. For instance, if someone were to import their wallet into Status via a seed phrase, and there are funds in the sectioned derivation path for the whisper key by happenstance, what would happen? Or the opposite? Maybe we craft an EIP for standardizing a derivation path for whisper keys, assuming that whisper takes off, it might be reasonable.

1 Like

@petty yes it’s a good idea! Just having a purpose field for whisper or something like “chat” would help I think

I don’t agree with decoupling them, for the reason that Corey mentioned and also
It is useful to send cryptotokens to a key that you only know you are speaking with.

We were planning to allow multiple wallets generated in the wallet anyway, which can also be whisper identities, there’s no distinction between keypairs.

So to me it seems easier, more featureful and encapsulates the security goal presented here to instead leave as is, but implement the derivation paths that support new wallet generation, and then make the first newly generated wallet the default one. So in a sense it is decoupled, but doesn’t prevent the use-case of sending to a person you only know their public key (address) of.

You can get the desired effect without breaking changes, and doesn’t prevent Status from accessing funds sent to some public key that Status has broadcasted.

We hack Whisper to inject keys into it’s keyring, by design (and for good reason) whisper keypairs are supposed to be ephemeral

hey @jarradhope! we haven’t started working on this yet, and I’m happy to change it if we find a better solution!

So to me it seems easier, more featureful and encapsulates the security goal presented here to instead leave as is, but implement the derivation paths that support new wallet generation, and then make the first newly generated wallet the default one. So in a sense it is decoupled, but doesn’t prevent the use-case of sending to a person you only know their public key (address) of.

Do you mean using m/44'/60'/0'/0/0 for whisper and m/44'/60'/0'/0/1 for the first wallet (and unique for now)? currently we the same exact key for chat and wallet (m/44'/60'/0'/0/0).

For instance, if someone were to import their wallet into Status via a seed phrase, and there are funds in the sectioned derivation path for the whisper key by happenstance, what would happen?

We would like to use a derivation path that is not usually used for wallets, so that importing a mnemonic created for example in metamask would use the usual m/44'/60'/0'/0/i for wallets but not for whisper keys.

You can get the desired effect without breaking changes, and doesn’t prevent Status from accessing funds sent to some public key that Status has broadcasted.

If the public key broadcasted is the whisper key, this means the wallet is still using the same key doesn’t it? maybe I missed a point here sorry


Another reasons why we talked about decoupling the keys are is the hardware wallet.
The private key derived at m/44'/60'/0'/0/0 is used to sign transactions, and it should never leave the card. we send data to be signed to the card and we get back the result. If the whisper identity is the public key derived from the same path, we need to inject that same private key in whisper to sign messages. this is the reason why we thought to keep the standard m/44'/60'/0'/0/i paths for wallets (0 for now and i when we’ll support multiple wallets for the same accounts), and having a different derivation path for the whisper identity.

We were planning to allow multiple wallets generated in the wallet anyway, which can also be whisper identities, there’s no distinction between keypairs.

I thought we could have multiple wallets in the same account but just 1 chat address.

A few thoughts about this issue from the hardwallet point of view.

  1. Whisper key(s) and account key(s) will not be fully decoupled since they are different paths derived from the same root. This means that the 12 (or 24) word mnemonic will be able to restore the entire hierarchy at once, no matter how many Whisper or transaction identities we have.

  2. If we use the Whisper key as the main ETH/SNT wallet account, then we lose one of the main advatanges of the hardwallet, which is keeping the private key away from the client device. The Whisper key is transfered on every login to the client so it is more vulnerable than a key generated and used only for transactions.

  3. Point 2 does not mean that we must preclude the usage of the Whisper account as a wallet altogether. But perhaps it would be helpful to make the user aware of the risk of keeping funds on the Whisper account and provide a one-touch way to transfer them to the main account. It could be even configured to do so automatically, since the client has the private Whisper key at all times when logged in.

In short, my point is that for optimal security (at least when using a hardware wallet), the client should do everything possible to make the user not use the Whisper account for transactions, provide a way to transfer funds from Whisper to “main” account but still provide access to funds eventually present on the Whisper account)