Below is a high level description of the mechanics of the Umbra protocol: 1. Users publish signed messages to ENS text records to reveal their Umbra public key. This public key is derived from a random private key specifically generated for use with Umbra. 2. A payer uses this public key, plus some randomly generated data, to create a new 'stealth' address. 3. The payer encrypts the random data with the receiver's public key. 4. The payer sends the funds to the stealth address and sends the encrypted message to Umbra's smart contract. The contract broadcasts the encrypted message as an Event. 5. The receiver scans the encrypted messages broadcast by the Umbra contract until they find one they can decrypt with their private key. 6. The receiver uses the contents of the encrypted message, plus their private key, to generate the private key of the stealth address. 7. The receiver uses the private key of the stealth address to sign a withdrawal transaction, sending the ETH or tokens to the address of their choice. 8. Optionally, the withdrawal transaction is broadcast via Gas Station Network transaction relayers, obviating the need to fund the stealth address to access tokens. The Umbra contracts swap some of the tokens via Uniswap to pay the GSN relayer for gas.
How It's Made
We'll walk through the above description and cover the technologies used at each interaction with the Umbra protocol. When a recipient first sets up their account, they need to purchase an ENS domain. Their Umbra private key signs a message, and this signature is stored as a text record associated with their ENS domain. This allows anyone to recover the recipient's public key from the signature associated with their ENS domain. When sending funds, a random number is generated with ethers, and we again use ethers to recover the public key and the elliptic library to compute the stealth address. The eccrypto library is used to encrypt the random number with the recipient's private key. The payer then calls a function on a Solidity smart contract to send the funds and announce the encrypted random number and associated cryptographic parameters. When the recipient retrieves funds, ethers is used to scan for all emitted announcements from the contract, and eccrypto is used to decrypt the announcements so the random number is accessible to the receiver. We use ethers to compute the new stealth private key. If ETH was sent, the user just transfers the ETH from the stealth address to any address of their choice. If tokens were sent, the GSN is used so they can withdraw tokens without needing to fund the stealth address with ETH. The frontend was built with Vue.js and Quasar Framework, and the contract testing and deployment was managed with various OpenZeppelin tools