Musings on Key Management (aka 'Whisper Decoupling')


#1

Finally had a few hours this Sunday to think about the Key Management stuff.

Background

We strive to be a private means of communicating, whether that is via text, media or transactions. However currently, it is easy to see a user’s entire transaction history (public blockchain’s yo) based on whisper identity. To improve this there is a desire to generate new keypairs for both on-chain transactions and communication.

Previous discussions have been thoughtful & fruitful, but have had some issues addressing backwards compatibility. In this document, I want to propose a slight variation on the view on keypairs, offer some thoughts on UI and point out some high impact low hanging fruit user feature ideas, while keeping backwards compatibility in mind.

Note: With these changes we do not solve the privacy issue, as transactions will still be traced, however this approach immediately discovering transactions from a user’s whisper identity is substantially harder and creates a solid foundation to support solving the issue with transaction privacy such as AZTEC protocol in the future.

Bonus Wall of Shame Item! Transaction Privacy!

For previous conversations see @gravityblast’s:

Keypair Security Models

I would like to propose viewing keypairs not in distinction of their logical use but instead of their security model. This is to say keypairs in Status live under hot, warm and cold policies.

We should recognise that first, all Keypairs are in-fact logically equivalent. However all public keys can derive addresses but addresses cannot be reverted to public keys (that’s literally the security feature design), in other words:

All ‘Whisper Contact Codes’ are Wallets, but not all Wallets are Whisper Contact Codes.

This cannot be stressed enough and is a necessary concept to understand to retain backwards compatibility.

Hot Keypairs

These are in-memory generated keypairs, should be used for both Whisper & Wallets and do not explicitly require the user’s interaction for signing transactions or messages.

They are hardened child-derivations from the keypair currently used for Whisper in the application, derivations are deterministic based on;

  • chat-id
  • dapp/website hostname hash (open to alternative ways to do this)
  • integer? (i.e. point of sales tx id)

If a (on-chain) balance exists on these keypairs, the application should strive to automatically sign a (private) transaction to an address managed by a warm or cold policy when it is appropriate to do so (???).

Nonetheless manual transactions from hot keypairs (in the wallet) should be treated under a warm keypair policy, the user should still confirm signing of the transaction when sending a transaction.

Except under the case of designation of a ‘pin-less’ address, maintaining feature parity with Keycard.

Warm Keypairs

We can view these keypairs typically as traditional wallets. While whisper could be used here, it is not practical, as warm keypairs require explicit signing.

Note: Since all derviations come from master key, all usable wallets in Status are at least considered Warm keypairs.

Cold Keypair

This is a keypair that the Status application or Keycard has no control over. In Status it is a pointer to an address. It should ideally be a hardware wallet. The user can add as many cold wallet addresses as they like, for receiving only.

The hardware wallet may be another Keycard however this keypair should be refused to be loaded into the current application if designated under an account, and refuse to add the keypair as a cold wallet if it’s already loaded into the application, encouraging the user to maintain physical device separation.

Chat Considerations

hot root = current whisper key pair (afaik m/44'/60'/0'/0/2 ?) or whatever derivation structure specified on recovery screen (see Recovery section)

If a user wants a wholly new identity, they can logout and create a new account. Otherwise we can treat the hot root public key as their identity. This will allow us to maintain backwards compatibility, while providing unique identities per chat context moving forward.

All new clients should enter chats (1-1, private group, public) with a hardened (uses hot root private key) child-derivation off the hot root public key (iirc).

The user’s identity is unique to the chat context they are in. This allows the client to reveal the user’s true identity. Revealing is a signed message by the private key of the hot root authorising the unique identity, encrypted with the receiving clients public key, the receiving client decrypts & uses ecrecover to verify.

The ENS username will most likely host the hot root public key and this key is likely the signer of reveals, the client listens on this keypair for inbound contact requests and shouldn’t be used for transmitting messages in the future, but will be during N future releases period.

Moving forward it will be impossible to directly chat (or transact?) with anyone based on the hot root, however we will introduce a transitionary phase that lasts N future releases where existing contacts can still converse directly with hot root public key, but encouraged to upgrade. New clients can still listen to messages received on the hot root public key, but older clients would see responses in new chats from new public keys.

When joining 1-1 or private group chats, the client can automatically reveal themselves to their friends/added contacts. And can selectively reveal themselves to unknown contacts.

An advanced option toggle would allow the user to intermediate all automatic functions, requiring explicit consent before automatic reveals.

A reveal to a friend could also automatically be responded to in-kind with a reveal, and subject to intermediation by advanced option.

Joining Public Chats is more complicated. Since child derivations are hardened, it is not possible, or desireable to automatically derive possible keypairs based on chat-id’s. Nor is requesting every contact every time you join a new event.

To minimise bandwidth, we could construct a bloom filter that aggregates all chat-id’s and passes it to the most recently seen/‘online’ contacts, this should be done on chat join events. This would allow clients to query bloom filters locally and give plausible deniability opportunity to the end client (assuming they are intermediating their reveals). If the user is no longer in that chat, the response is dropped.

The user should also be able to explicitly reveal to another user who they are in a public chat.

This would mean that a user will have a ‘wallet’ or address for every Chat context. (See Wallet section)

DApp Considerations

Each DApp would also have their own key, a hardened child-derivation off the hot root based on hostname hash (or better? open to ideas).

With this approach we can offer a ‘proxy’ address to the DApp, in which we send a (private) transaction to, to be used to the DApp, and, since it is a hot keypair, we can also offer a streamlined user experience with the ability to ‘Not ask me to sign transactions’, this would require ‘preloading’ the DApp Address with X value, this allows the user a degree of control without excessive transaction signing.

This would mean that a user will have a ‘wallet’ or address for every DApp context. (See Wallet section)

User Interface Considerations

~~~~~~~~~~~~~~~~ [2:37] Intermission ~~~~~~~~~~~~~~~~

Tangential but important & easy wallet improvements

  • 24 word phrase recovery should be possible, please make it an option.
  • Emoji Guard,
    Seriously, it’s better than confusion between keyphrase and 3 words. and better than not having anything. Application proving itself to the user is important.
    Edit: This has been an issue for over a year now with no new improvements from anyone, if no one has better ideas and the current version is tied to a linguistic background that not all users are guaranteed to have then I vote we go ahead with this.
  • Omgplz let me add custom tokens already.
  • Social Recovery by splitting Key. (okay this isn’t as easy, but gogogo!)

Chat & DApps

In this setup, chat remains largely unchanged, most of the work is ‘under the hood’ and is backwards compatible.

However we will need to develop UI flows to do reveal.

Older clients that did not upgrade within the ‘N future releases’ period will see mysterious responses in new chats from unknown public keys. I don’t think this should be a concern.

The important difference here is that now Chat & DApp tab items can essentially hold their own balances. (See Wallet section)

Wallet

You should be able to send and receive from any key.

The wallet screen remains unchanged and is an aggregate of the user’s assets under all wallets.

The wallet should enumerate all addresses under hot, warm and cold that are used by the client, it should be a list ordered by their respective balances, displaying the top 3 token balances in each list item. To pull this off, wallet needs to be more responsive & intelligent in how it caches and queries balance data.

That means the list should be populated with 0 ETH balance DApp and Chat Addresses. It entirely possible to include this information in the current tab list and introduce a new Wallet tab list type. If these items are just generic new wallets, tapping them takes you to the existing wallet interface, but for that specific address, if it is a chat or dapp, it takes you do the chat/dapp, however we already have “View My Wallet” in 3 dots, conceptually this could be “View DApp Wallet, or View Chat Wallet”

Creating a new wallet is just an integer child-derivation from warm root. Creating a new wallet is client-side only. On recovery these will be forgotten (unless they have balance) until we can encrypt the application database and upload to decentralised file storage.

Creating a cold wallet is read-only, receive only and requires the user to enter in an address. That is not under control of the application.

This also allows us to create smart contract based wallets, ie multisig, but I think this should be the next iteration.

A wallet address can be revealed in a chat context that is seperate from the unique identity and the real identity via the send/request commands.

This approach allows us to re-use many existing flows and UI elements without introducing major breaking changes or too many new UI elements. I imagine most of the work would be efficiently managing the balance data.

Recovery

Since we made efforts to use similar key phrase recovery as other applications, Status should be compatible with any other HD key structures, such we should auto-detect what structure the recovered keypair uses based on other popular applications compatible with BIP44, and/or offer the user to select or define their own structure.

It might even make sense to support multiple HD key structures, as users might use the same keypair on different applications.

While I’m at it, by now we should also offer to import other private keys into Status

Conclusion

The above suggestions seem to achieve our goals while keeping minimal UI changes and retaining backwards compatibility, I have used some terms interchangeably and probably have some terms wrong (it’s been awhile)

(Also why does the Wallet say ‘Deposit’ instead of Receive? Not very accurate imo)

I’m sure I’ve missed some considerations and would love feedback!


#2

Hey @jarradhope thanks for this topic! There are a lot of things I would love to discuss about but I’ll try to write a quick reply before we have the dev meeting. Then I’ll add more questions/ideas.

hot root = current whisper key pair (afaik m/44’/60’/0’/0/2 ?) or whatever derivation structure specified on recovery screen (see Recovery section)

The current whisper key pair that we use is the same of the first BIP44 wallet we use, so for now it’s m/44'/60'/0'/0/0

The initial idea was to use EIP1581 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md for chat keys, and in general for hot keys that can be exported from the keycard.

If we have in mind to have warm and hot keys, do we still need to decouple whisper (hot), and wallet (warm) so that they are manage in different ways?

If a (on-chain) balance exists on these keypairs, the application should strive to automatically sign a (private) transaction to an address managed by a warm or cold policy when it is appropriate to do so (???).

Just to see if I understood: if a hot wallet has a balance, the app helps the user to move the balance to a warm or cold address. correct?

Warm Keypairs
We can view these keypairs typically as traditional wallets. While whisper could be used here, it is not practical, as warm keypairs require explicit signing.
Note: Since all derviations come from master key, all usable wallets in Status are at least considered Warm keypairs.

If I understand correctly, a BIP44 wallet is a warm wallet. So it’s basically what we have now as the only visible wallet, but we should not use the same key for whisper like we are doing now.

Cold Keypair

so here we can have view only addresses right? in case of keycard, any BIP44 will be a view only address, so only the address is kept in memory, never the actual key.

Each DApp would also have their own key, a hardened child-derivation off the hot root based on hostname hash (or better? open to ideas).

This is a good idea, although we can do it only with dapps with a domain. (.eth or any other domain).

What can we do if it’s just on ipfs/swarm? maybe we can use the ipfs hash, but then an update of the dapp will change it.
Related discussion: https://ethereum-magicians.org/t/meta-we-should-value-privacy-more/2475


#3

Very much this! I’ve mentioned earlier in previous posts that a coupling of chat and wallet keys means you’re treating the security of one the same as the other. I’d like to verify that you are detailing this out in your post, but also reminding us that “whisper keys are still wallets, so they also need to provide that functionality just in case it is needed” (to rephrase the post).

I’d also like to see how we can update the schematics of key derivation and management I’ve created and linked in the first historical post you linked. I believe those help us reason and intuit the uses of keys for Status, as well as outside contributors when evaluating us.


#4

My understanding is that using the current whisper key (m/44’/60’/0’/0/0) as the hot root is necessary to allow backwards compatibility in this proposal. Is that right?

If yes, one thing that bugs me is that when Keycard is used, the hotroot keypair should be exported from Keycard, and we had planned to allow export only on a set of paths (m / 43’ / 60’ / 1581’/x/x) defined in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md

Another way to put the problem: if we decide that the hotroot is down that path (m / 43’ / 60’ / 1581’/x/x), how much harder backwards compatibility gets?


#5

hot root should be fine to be exported to a trusted device as it’s living in memory anyway.

if you change the derivation path, and do not expose it to the client, then it is unable to decrypt messages send to that pubkey and it wouldn’t be unable to sign transactions, important if you want to change ens username ownership.

I’m not opposed to the derivation path change, but OP was kind of making a minor case against the idea of seperating keys out by their logical use in the derivation path, since there’s nothing technically stopping keys from being used for either approach, and if the team responsible for the changes is not fully aware of the consequences I’d recommend against doing it, at least for this iteration.

You would have to:

  1. Export the original hotkey
  2. Remove all responsibility from the key, ensure the user/client has moved all assets, notified all contacts (and dapps) of the change to the new key
  3. Log user out, have them sign in again under new derivation path.

2 is fairly problematic, if you give them no ability to define their own hd key structure then you are potentially locking a user out of their assets, which is why I was suggesting we include this in the recovery screen for advanced users.

That would mean that for new accounts we can use a new derivation path, but we still autodetect and use our current derivation path, as well as ledger/metamask/etc key structures


#6

Thanks !

I have a hard time figuring out what should be the exact path of the hotroot that would best take into account the following constraints. Please challenge them, they need to actually :slight_smile:

  • Current implementation of Keycard imposes hotroot to be on m/43’/ 60’/1581’/x/x paths
    Current Keycard code only allows to export the key pairs of the following paths m/43’/ 60’/1581’/x/x. This is how it is implemented, and we issued EIP-1581 to try to normalize this.

  • Hotroot can not be m/44’/60’/0’/0/0 for Keycard security
    Keycard should not be able export m/44’/60’/0’/0/0, since it sounds quite contrary to its fundamental to be able to export such a common BIP44 wallet path (and our current wallet path)

  • Hotroot should be m/44’/60’/0’/0/0 from a migration standpoint
    Since our current whisper key is m/44’/60’/0’/0/0, if hotroot is different than m/44’/60’/0’/0/0 then we have to go through your steps 1-2-3 below which looks like a no go in terms of user experience

And to focus on the keycard, what we have to decide now is if we think and implement a new security scheme to allow/forbid export of key pairs than the one currently implemented!