Asymmetric Key for mobile-to-mobile


Following the discussion of WalletConnect Meeting on 25th July, where we explored deep linking communication between a mobile Dapp and mobile Wallet, the main concern was that deep linking services could listen to the symmetric key currently used for mobile-to-desktop breaking the encryption between the dapp and wallet. The suggestion was to include an asymmetric key encryption to protect from this use-case which would require WalletConnect to check and adapt for mobile-to-mobile.


I see some advantages for asymmetric keys despite from the mobile-to-mobile case.

  • first one is a bit constructed - but just to show I see some attack surface that does not need to be there: e.g. a hacked webcam + reflections in you glasses or a camera that looks over your shoulder and the attacker could listen to your communication and in the right time submit his own transaction and blocking your communication.
  • less dependencies (e.g. in WallETH I want to get rid of spongycastle - the need for these new crypto primitives will bind me more to it)
  • we could use the public keys as sessionId and maybe get shorter urls this way ( see also )
  • easier upgrade path to pss/whisper

That all said: I don’t feel extremely strongly about it. Getting the UX right first is more important. I think we mainly should keep upgrade paths open and I would love to know why symmetric was chosen in the first place.


There are 2 URL schemas for iOS: Deep Links and Universal Links. Here’s the info about the difference -

I think if for iOS we use Deep Links (not Universal Links) we should be fine using the symmetric key. I believe Viktor from Trust Wallet knows more than me :slightly_smiling_face:


As discussed in the Telegram group,

In order to support multiple wallets with mobile-to-mobile links, we can point the link to a WalletConnect web page. On the page user can be prompted to choose an app from a list of wallets.

The list of wallets can be curated with an open-source registry on the WalletConnect’s Github repo.

Here’s an example how this can look like -


I like the idea of an asymmetric key agreement too. Concur with all your points.

Some less constructed ideas of attack vectors:

  • A virus that watches QR codes. Horrifyingly, there’s been demonstrates of programs that hot-replace Bitcoin address QR codes on a display with a new QR code. I’m not sure if these are in the wild yet, but they could be.
  • dApp(s) mishandling the session key, and it gets stolen. This might sound hard, but consider lots of developers include off-site scripts by web 2.0 habit (e.g. tracking scripts, libraries) — if a hacker is able to poison just one of those JS URLs, they’ll have complete access to anything the dApp has access to.


The attack vectors can be summarised to:

1. URI/QR data reaches attacker instead of destination.
2. URI/QR data reaches destination, but also attacker.

We need to solve for both. I’m more scared of the second because it wouldn’t be obvious, and a fraudulent request could pop up any time in 0-24 hours.

To protect from the second (man-in-the-middle attack), the wallet could remember the first sender/dApp, and break when the sender changes. This doesn’t help with the first, though.

For example (spitballing — there’s certainly something better):

  1. dApp generates an ephemeral key pair.
  2. dApp registers its public key with the bridge. Bridge relays all messages addressed to the public key (no need for a session ID).
  3. QR code or deep link contains bridge address and dApp’s public key. Wallet scans.
  4. Wallet generates its own ephemeral key pair.
  5. Wallet sends its public key to the bridge, addressed to the dApp’s public key. Bridge relays all messages addressed to the public key to the wallet.
  6. dApp remembers the wallet’s public key.
  7. For every message, the dApp creates the following, encrypts it to the wallet’s key and sends it to bridge (addressed to the wallet’s public key):
    • the command incl. data (e.g. transaction, ping, whatever)
    • a signature of the command incl. data signed with the dApp’s private key
  8. When wallet gets a message, it recovers the dApp’s public key from the signature.

If attacker wallet comes along later and sends a message, dApp will ignore it because it already has a wallet public key. There’s no way for the attacker to know the dApp’s private key.

Other benefit of a key agreement protocol: even if the QR/data eavesdropper colludes with the bridge, they can’t decipher the messages because they have no private key.

Edit: Actually, the above is bad because the bridge has the public key; a bad bridge could be the first to respond. You could easily fix that by including a secret in the QR/URI as well (which the bridge can’t know).
Edit: Realised mistakes.

Something else (much better IMO), with an anonymous key agreement protocol:

  1. dApp generates an ephemeral key pair.
  2. dApp registers its public key with the bridge.
  3. Anyone can “tune in” to messages addressed to the public key (it’s also the session ID).
  4. QR code or deep link contains bridge address and dApp’s public key. Wallet scans.
  5. Wallet generates its own ephemeral key pair.
  6. Wallet sends its public key to the bridge, encrypted and addressed to the dApp’s public key.
  7. Both wallet and dApp now have each other’s public keys, and their own private keys. They use the ECDH function to derive a shared secret from the public/private key pairs (i.e. dApp’s private, wallet’s public or wallet’s private, dApp’s public).
  8. The wallet begins listening to messages addressed to the dApp public key. That public key isn’t used for anything other than a session ID anymore.
  9. For every message, the sender encrypts the message to the shared secret and sends it to bridge, addressed to the public key.
  10. Receiver can decrypt the message with the shared secret.

Accomplishment: QR data was just needed for the initial handshake. After the handshake, both clients agreed on a new key (the shared secret), and the ephemeral keys are now useless (besides the public key as the session ID).

Also, this enables two-way communication; in my previous less-thought-out idea I didn’t think about communication from the wallet to the dApp.