[RFC] Opaque: Preventing Identity Linkage for ENS Names (EIP-5564 Implementation)

Why I Built This

I love ENS, but I have a confession: I don’t actually use the wallet linked to my primary .eth name for my daily transactions. Like many of you, I don’t want every person I send 20 USDC to, or every observer on-chain, to know exactly how much I have in my main vault, where I spend my money, or what my total net worth is. Currently, ENS is the best identity system in Web3, but it’s also a massive “privacy leak” because it perfectly links a human-readable name to a transparent financial history.

I built Opaque because I wanted to stay within the ENS ecosystem while maintaining the basic right to financial privacy that we take for granted in the physical world.

What is Opaque?

Opaque is an open-source, non-custodial privacy layer built on EIP-5564 (Stealth Addresses). It allows users to receive ETH and ERC-20 tokens at unique, one-time “stealth addresses” that are cryptographically derived from their ENS name or Meta-Address, but are unlinkable to it on-chain.

The protocol is not just a “concept”, it is fully built and functional on Sepolia right now.

Technical Architecture: How it Works

Opaque is a reference implementation of EIP-5564, designed to be a reusable infrastructure layer. It utilizes a Dual-Key Stealth Address Protocol (DKSAP) on the secp256k1 curve.

1. The Key Derivation Logic Instead of a single public key, a user registers a Stealth Meta-Address (M) consisting of two public keys: a spending public key (K) and a viewing public key (V):

M = (K, V)

To send funds, the sender generates an ephemeral private key (r) and its corresponding public key R = r * G. They then compute a shared secret (S) using the recipient’s viewing key:

S = r * V = v * R

The destination stealth address (P) is derived by “tweaking” the spending key with the hash of this secret:

P_pub = K + hash(S) * G

The recipient, owning the private viewing key (v) and private spending key (k), derives the one-time private key (p) to control the funds:

p = k + hash(v * R)

High-Performance Scanning (Rust-WASM)

Since recipients must check every “Announcement” on-chain, performance is the primary bottleneck. We implemented a Rust core compiled to WASM that uses View Tags (the first byte of the shared secret hash) to skip 99.6% of irrelevant transactions before performing expensive point addition. This ensures the protocol remains responsive on mobile devices.

Beyond the Standard: Reusable Infrastructure

I didn’t build this to be a standalone app; I built it to be infrastructure that solves real-world UX hurdles:

  • The “Gas Tank” Utility: The biggest privacy pitfall is funding gas. Users often de-anonymize stealth addresses by sending ETH from their main wallet to pay for a sweep. We implemented a Deterministic Gas Tank derived from the user’s keys. For tokens supporting EIP-2612 (Permit), the Gas Tank pays the fee while the stealth address remains unlinked.
  • Manual Ghost Addresses: EIP-5564 assumes the sender supports the protocol. Opaque allows users to generate “Ghost Addresses” for receive-only flows from legacy or external wallets. These can be retroactively announced on-chain using a deterministic Announcer identity funded by the Gas Tank, ensuring your main .eth wallet is never the on-chain caller.
  • The Registry: We utilize the EIP-6538 Registry. Any project (wallets, dApps, or ENSv2 resolvers) can query this registry to enable “Privacy-by-Default” for their users.

Example Use Cases

  • DAO Contributor Privacy: Receive grants or work payments without exposing your cumulative earnings or other DAO participations.
  • Merchant Privacy: Accept payments via your ENS name without revealing your store’s total revenue to competitors or the public.
  • One-Time “Ghost” Addresses: Generate a stealth address for a one-off payment from a legacy wallet that doesn’t yet support EIP-5564.

I’m looking forward to hearing your thoughts and honest feedback on the implementation.

8 Likes

Hey thanks for posting this and for the detailed write-up. The implementation looks like solid work.

The stealth address space has seen a lot of development since Vitalik’s original post. Umbra (whose team co-authored EIP-5564) is live on mainnet with 85K+ transactions, and Fluidkey was recently featured on the ENS blog with native ENS subdomain integration and a full wallet experience. For a new proposal in this space to clear the bar, we’d need to see clear differentiation from what already exists and is funded.

None of this takes away from the quality of the build itself. Let’s get the prior grant squared away and we’re happy to look at future proposals with fresh eyes.

4 Likes

Thanks for sharing this — really interesting direction.

I’m curious how you see this approach comparing to existing implementations like Fluidkey. From a user perspective, Fluidkey already provides a fairly smooth stealth address experience that seems quite similar to what’s described here.

If this proposal were implemented at the ENS level, what do you see as the key advantages or differences in terms of user experience and integration?

1 Like

Thanks for the feedback. To clarify, this is just an RFC for technical feedback, not a formal grant proposal.

Most current tools still struggle with the “last mile”, funding gas for stealth addresses often de-anonymizes the user. Deterministic Gas Tank solves this at the protocol level, keeping the identity linkage broken even during the sweep.

Fluidkey is definitely a solid implementation. Opaque’s focus is slightly different, specifically targeting two infrastructure hurdles:

  1. Gas Linkage: Using a deterministic Gas Tank and EIP-2612 to ensure the stealth address remains unlinked during the ‘sweep’ phase.
  2. Legacy Interop: Our ‘Ghost Address’ feature allows users to receive privately from wallets that don’t yet support EIP-5564.

I appreciate the insights and will continue to look into how this can best complement the existing tools in the space.

2 Likes