ERC-5564: Improving Privacy on Ethereum through Stealth Address Wallets

Privacy represents a fundamental human right. Especially in the context of financial transactions privacy is of particular importance. Public blockchains like Ethereum ship built-in transparency that allows anyone to track transactions across the publicly accessible ledger, posing many challenges for privacy.

Crypto assets, no matter if they are native blockchain assets such as ETH, tokens, or NFTs, all entail the risk of revealing sensitive private information about the owner to unintended third parties.

E.g. People who buy a concert ticket in the form of an NFT may not want to share their entire financial record, including information on how much money they have and what they spend it on, with the event organizer or security staff.

Privacy can be implemented on different layers of a blockchain: Like Zcash, zk-SNARKs can be used to hide sensitive information already on the protocol layer. This comes with massive benefits on the privacy front, however, introduces complexity and possible compliance issues to related ecosystems.

Privacy enhancements implemented on the application layer have been around for several years now. While Bitcoin has wallet applications such as Wasabi Wallet that effectively obfuscate Bitcoin money flows using CoinJoins, Ethereum has tools such as Tornado Cash that use zk-SNARK technology to mix assets for hiding the true ownership.

Application layer standards can help the proliferation of privacy, however, depend on actual applications implementing them.

Stealth Addresses are a perfect example of a standardizable technology that can bring significant benefits to on-chain privacy while entailing negligible complexity and great backward compatibility.

What are Stealth Addresses?

Stealth addresses are a rather old concept (old in crypto-time) and have been introduced by Peter Todd, already in 2014 [1]. Stealth addresses are essentially addresses to which the sender can send funds, knowing that only the targeted recipient can generate the appropriate private key to access the funds. This way, stealth addresses look like random addresses in the eyes of blockchain analysis and do not compromise sensitive information about the true owner.

This concept enables you to send an NFT to vitalik.eth (actually to a stealth address that only you and Vitalik would know), without letting the rest of the world know that Vitalik just received an NFT. You can airdrop a concert ticket to the stealth address of another person and can be sure that only(!) this person (the recipient) will be able to access the funds. For every other observer, it looks like someone received a ticket, leaving no opportunity to link the stealth address to the address of the true owner.

Vitalik provided a great explanation of how stealth addresses can be implemented practically:

Vitalik Buterin describes Stealth Addreses

For sending funds to the stealth address of another person P, the sender would take the public key P and generate a shared secret q using a generated secret value s and P.
Additionally, the sender computes the public key S to the chosen secret and publishes it.
Importantly, the shared secret q can also be generated by the recipient by using pand S. Summarizing, q = s * P = p* S.

Q represents a shared secret between the sender and recipient. The sender then takes the hash of q and generates a new public key Q from it.

Following, by performing an elliptic curve addition of Q and R, a new Stealth Public Key is derived, from which the final stealth address stA can be derived.
The magic here is hided in the elliptic curve addition using the shared secret: The recipient can add the value q to his own private key r to retrieve the private key that can eventually unlock the funds at stA.

In summarizing, the sender can generate a (fresh) stealth address to which only the recipient has access, without requiring any interaction with the recipient upfront. Using this stealth address, the sender can obfuscate the recipient’s true identity. The sender only has to publish the public key to the chosen secret (S), so that the recipients know that they were the recipient of a transfer.

Find a quick, Python-based Proof-of-Concept of Stealth Addresses here.

What is ERC-5564 about?

ERC-5564 originates from a proposal to improve the privacy of NFTs by using zk-SNARKs. The original proposal was drafted for ERC-721 tokens and required Merkle Trees and zk-SNARKs, both entailing high complexity.
Vitalik Buterin then had the idea of using stealth addresses without any other heavy-weight cryptographic overload:

After initial discussions on how to implement a related standard through an ERC, the best and most generalizable way to accomplish it was trying to implement it into a Smart Contract Wallet.

https://ethresear.ch/t/erc721-extension-for-zk-snarks/13237/15?u=nerolation

Smart Contract Wallets are essentially the same as normal Ethereum Accounts (EOAs) but are controlled through some additional code – the smart contract. This enables Smart Contract Wallets to implement more sophisticated functionalities such as multi-signature schemes, recovery features, or stealth address support.

The most prominent examples are Gnosis Safe, Argent, and Authereum.

Smart Contracts Wallets, in contrast to custodial wallets which users have on Binance, Kraken, etc. are still non-custodial. This is because the wallet is still controlled by the user without requiring third-party custodians.

What is needed to implement ERC-5564?

  • Smart contract wallets MUST encode the public key of the wallet directly into the contract
  • Smart contract wallets MUST offer a standardized function to generate stealth addresses on behalf of other users.

interface IERC5564 {

     bytes publicKey;

     function generateStealthAddress(uint256 secret)
     returns (bytes publishableData, address stealthAddress)
}

Users can locally execute the generateStealthAddress function on the recipient’s wallet to retrieve a stealth address that can be accessed by the recipient.

  • An immutable contract may take over the role to broadcast the publishable information S (Public key to s ) and the stealth address for every kind of transfer.

interface PubStealthInfoContract {
     event PrivateTransfer(address indexed stealthRecipient, bytes publishableData)
}

This information is needed by the recipients to know that they have received some asset: Recipients parse all broadcasted S values, compute a shared secret Q, and then a stealth address stA. Only if the derived stA equals the address broadcasted together with S, you can be sure that you were the recipient of the respective transfer.

Practically, a possible implementation of ERC-5564 may look like drafted here.

Open Challenges

The biggest challenge that stealth addresses entail is the question of paying transaction fees. If you send an NFT to the stealth address of someone, then the recipient cannot send it to someone else without first funding the account with some ETH to pay the fees.
This constitutes a privacy risk because the funds to cover the transaction fees could again reveal sensitive information about the true owner.

In general, there are two ways to solve this problem [1]:

  • Use anonymized funds (Mixers)
  • The recipient should sponsor some transactions by attaching some ETH to every transfer.

For NFT tickets that are not required to be moved frequently between users, the sender can also send the NFT without sponsoring any further transactions. The recipient is still able to prove ownership.

The are other open points for discussion:

  • A single contract to emit the privateTransfer Event?
  • Add function to directly attach some ETH for sponsoring tx fees?

Additional ressources

References

[1] Peter Todd, https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2014-January/004020.html

[2] Vitalik Buterin, https://ethresear.ch/t/erc721-extension-for-zk-snarks/13237/2

Photo by fabio on Unsplash