Overview
Stealth addresses are one-time addresses that allow buyers to receive on-chain assets (receipts, warranties) without revealing their identity or creating an on-chain transaction graph. Each payment generates a fresh, unlinkable address that only the buyer can detect and spend from.Stealth addresses provide receiver privacy: observers see payments to unique addresses but cannot determine who controls them or link them to other payments.
Key concepts
Address derivation
Each buyer has two public keys:- Spend public key (
K_spend): Ed25519 key for signing transactions - View public key (
K_view): X25519 key for ECDH and payment detection
Generate ephemeral keypair
Create a random X25519 ephemeral private key
r and compute R = r·G (ephemeral public key).Derive stealth scalar
Compute
s = SHA-256(shared || "identipay-stealth-v1") where the domain separator prevents cross-protocol attacks.View tags for fast scanning
Without optimization, buyers would need to perform an ECDH computation for every payment announcement on the blockchain - expensive for wallets scanning thousands of transactions. identiPay uses view tags to accelerate scanning by ~256x:stealth.service.ts
Implementation
Sender-side derivation
The backend service implements stealth address generation:stealth.service.ts
stealth.service.ts
The implementation uses X25519 for ECDH (optimized for key exchange) and Ed25519 for the stealth public key derivation (compatible with Sui addresses).
On-chain announcements
When a payment is sent to a stealth address, the sender emits an announcement event that the buyer can scan:announcements.move
announcements.move
Receiver-side scanning
The buyer’s wallet scans announcement events to detect incoming payments:stealth.service.ts
Payment flow
Spending from stealth addresses
To spend from a stealth address, the buyer must derive the corresponding private key:- Detect an incoming payment using
scanAnnouncement - Compute the shared secret:
shared = x25519(k_view, R)wherek_viewis the viewing private key andRis the ephemeral public key - Derive the stealth scalar:
s = SHA-256(shared || domain) - Compute the stealth private key:
k_stealth = k_spend + s(scalar addition mod curve order) - Sign transactions using
k_stealth
Privacy properties
What observers see
On-chain observers (block explorers, analytics tools) can see:- Payments to unique addresses that are never reused
- Ephemeral public keys and view tags in announcements
- Which stealth addresses receive assets
What observers cannot see
- Who controls a stealth address (no link to the buyer’s identity)
- Which stealth addresses belong to the same buyer
- The buyer’s viewing or spending keys
- Whether two payments are to the same recipient
Stealth addresses break forward tracing (following payments from a known address) and backward tracing (finding the source of funds to an address).
Security considerations
Ephemeral key generation
Ephemeral key generation
The security of stealth addresses depends on generating cryptographically secure random ephemeral keys. The implementation uses:This uses the
@noble/curves library which sources randomness from crypto.getRandomValues() (browser) or crypto.randomBytes() (Node.js).Domain separation
Domain separation
The stealth scalar derivation includes a domain separator:This prevents cross-protocol attacks where the same keypair might be used for different purposes. The domain separator ensures that stealth scalars derived for identiPay cannot collide with other systems.
View key security
View key security
The view private key (
k_view) allows detection of incoming payments but not spending. This enables:- Wallet syncing across devices (share view key only)
- Third-party transaction monitoring (give auditor the view key)
- Light clients that detect payments without holding spend keys
- All stealth addresses controlled by the user
- Payment amounts and timing
- Links between different payments to the same recipient
Integration with shielded pools
Stealth addresses work in combination with shielded pools to provide complete payment privacy:- Buyer receives payments at multiple stealth addresses
- Buyer deposits funds from stealth addresses into shielded pool
- Buyer withdraws merged funds to a fresh stealth address for spending
Related concepts
Intent-based payments
Learn how buyers authorize payments without revealing identity
Shielded pools
Understand how to merge funds from multiple stealth addresses
