Shade How It Works?
Let’s start with how the Shade protocol (and more generally, stealth addresses) works:
The recipient has a public key P and a private key p. The sender generates a random number r, and uses elliptic curve multiplication to calculate the stealth public key P_stealth = P * r. The sender then derives the Ethereum address a_stealth from this stealth public key and sends funds to that address. Due to the properties of elliptic curve mathematics, the recipient can compute p_stealth to derive the private key required to access the funds at a_stealth, i.e., p_stealth = p * r.
The first issue to address is how the sender passes the value r to the receiver. If r were public, an observer could compute P * r and determine who the funds were sent to by matching it with the published P values. Therefore, r must be encrypted.
ECDH Encryption Process
Encryption is done through Elliptic Curve Diffie-Hellman (ECDH). That means the sender uses the recipient's public key to encrypt the random number. The encrypted random number becomes ciphertext c, and both the stealth address a_stealth and the encrypted random number c are announced. To complete the ECDH encryption process, the sender also generates a temporary private key p_ephemeral, and announces the corresponding public key P_ephemeral.
The recipient can then scan all the Announcement events on the blockchain to find their funds, as follows:
The recipient uses their private key
pand the temporary public keyP_ephemeralto compute the ECDH shared secret and decrypt the ciphertextc, obtaining the random numberr.The recipient then multiplies the decrypted random number
rby their private keyp, obtainingp_stealth, and computes the stealth address controlled byp_stealth.If the address controlled by
p_stealthmatches the stealth addressa_stealthincluded in the Announcement event, the recipient knows that the payment is for them and can usep_stealthto withdraw the funds.
Application Private Keys
As shown in the explanation above, the Shade protocol needs access to the recipient’s private key in order to perform the necessary cryptographic operations. However, when you connect your wallet to an application, the wallet does not share your private key with the application. This is crucial because if any application could access your private key, they could steal your funds. So how does Shade access your private key? We have a few options:
Ask users to input their wallet’s private key. This is a terrible idea from both a security and user experience perspective, so we don’t use this method.
Generate a random private key and ask the user to back it up. This approach works, but backing up application-specific keys is not ideal.
Ask users to sign a message, hash the signature, and derive the key from the signature. This option solves the problems with the first two methods and is the approach we use. Similar techniques are used by projects like Loopring and zkSync, and they served as inspiration for this method.
Scanning for Funds
The final consideration is related to scanning. Because the recipient needs to scan every Announcement event, it can take a long time to find their funds.
To speed up this process (from the user's perspective), we allow the scanning task to be delegated to a third-party service, which will notify the user when they receive funds. However, this presents a problem: scanning services need access to the recipient’s private key p to determine if they’ve received the funds. If they have access to p, they can steal the funds!
We solve this problem by generating two application-specific private keys:
One private key, view private key
p_view, is used to encrypt the random number.The other is the spend private key
p_spend, which is used to compute the stealth address and access the funds.
Sending and Receiving Process
Now, the sending and receiving process in the Shade protocol is modified as follows:
The recipient has two private keys:
p_spendandp_view, and publishes the corresponding public keys:P_spendandP_view.The sender generates a random number
rand usesP_viewand a temporary private keyp_ephemeralto encrypt it, creating the ciphertextc.The sender computes the stealth address
a_stealthderived fromP_spend * rand sends the funds to that address.The Shade contract announces the ciphertext
c, the temporary public keyP_ephemeral, and the stealth addressa_stealth.The recipient scans all Announcement events, and using
p_viewandP_ephemeral, decryptsr. They then check ifp_stealth = p_spend * rcontrols the stealth addressa_stealth.By doing this, the recipient can delegate the scanning task to a third-party service. The service can check whether the recipient has received the funds, but since the third party does not have access to
p_spend, they cannot spend the funds.
This method ensures that the scanning service can safely check if funds have been received, without having spending rights over the funds, providing a secure and efficient way for users to track and access their funds.
Last updated