Overview
The Announcements contract (identipay::announcements) provides a simple but critical function: emitting events that allow recipients to detect stealth payments without scanning the entire blockchain.
When a sender pays to a one-time stealth address, they emit an announcement containing:
- Ephemeral public key
R - View tag (1-byte filter)
- Stealth address
- Optional metadata
Source Code
Location:contracts/sources/announcements.move:6
How It Works
Payment Derivation
Sender derives a one-time stealth address
P using recipient’s meta-address and ephemeral key r.Announcement Emission
Sender calls
announce() with ephemeral public key R = r*G, view tag, and stealth address.Recipient Scanning
Recipient’s wallet scans announcements, filtering by view tag, then checking full ECDH computation.
Data Structures
StealthAnnouncement
Event emitted when a payment is sent to a stealth address.Ephemeral public key
R = r*G (32 bytes). Recipients use this with their viewing private key to derive the shared secret and detect payments.First byte of the ECDH shared secret. Fast 1-byte filter reduces full ECDH computations by ~256x during scanning.
The derived one-time stealth address where the payment was sent.
Optional encrypted memo (e.g., payment reason, sender hint). Can be empty.
Entry Functions
announce
Emit a stealth payment announcement. Called by anyone sending to a stealth address. Function Signature:Ephemeral public key (exactly 32 bytes)
First byte of ECDH shared secret for fast filtering
Derived one-time stealth address
Optional encrypted metadata. Pass empty vector if no metadata.
EInvalidEphemeralPubkey(0): Ephemeral pubkey is not 32 bytes
announcements.move:38-53
Usage Example
View Tag Optimization
The view tag is a critical optimization that reduces scanning costs by ~256x.Without View Tag
Recipients must:- For each announcement, compute full ECDH:
S = k_view * R - Derive stealth address:
P = K_spend + Hash(S)*G - Compare with announcement’s
stealth_address
With View Tag
Recipients:- For each announcement, check
view_tag == S[0](cheap byte comparison) - Only if match, compute full ECDH and derive address
- 1,000 byte comparisons (very cheap)
- ~4 ECDH computations (256x fewer)
Event Indexing
Announcements are indexed off-chain for efficient querying:Privacy Considerations
Address Unlinkability
Address Unlinkability
Announcements reveal stealth addresses but not recipient identities. Observers cannot link multiple stealth addresses to the same recipient.
Metadata Encryption
Metadata Encryption
Optional metadata should be encrypted using the ECDH shared secret. Only the sender and recipient can decrypt it.
View Tag Leakage
View Tag Leakage
The view tag leaks 8 bits of the shared secret. This is acceptable as the full shared secret is 256 bits, leaving 248 bits of entropy.
Sender Privacy
Sender Privacy
Announcements do not identify the sender. If sender privacy is needed, send from a stealth address and encrypt sender info in metadata.
Integration Patterns
Pattern 1: Settlement Module
The Settlement contract does not emit announcements directly. Instead, the buyer’s wallet emits the announcement as part of the PTB:Pattern 2: P2P Transfer
Direct stealth payments between users:Pattern 3: Shielded Pool Withdrawal
No announcement needed for pool withdrawals since the recipient address is chosen by the user:Security Considerations
Event Reliability: Sui guarantees event emission if the transaction succeeds. Failed transactions do not emit events, ensuring announcements always correspond to real payments.
Gas Costs: Emitting an announcement costs ~1,000 gas units. This is negligible compared to the overall transaction cost.
Related Modules
Meta-Address Registry
Resolve names to public keys for stealth derivation
Settlement
Uses stealth addresses for receipt delivery
