> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usewraith.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# How Stealth Payments Work

> Visual guide to stealth address cryptography

Stealth addresses let you receive payments at one-time addresses that can't be linked to your identity. This guide explains the cryptography in plain language.

## The Problem

On most blockchains, addresses are public. If you share your address to receive a payment, anyone can see every transaction you've received, track your total balance, and link your identity to all your financial activity.

## The Solution: Stealth Addresses

Instead of receiving payments at a single reusable address, each payment goes to a **fresh one-time address** that only you can detect and spend from.

<img src="https://mintcdn.com/truth/SJlfH_n1UHSFJ8ir/assets/diagrams/stealth-comparison.svg?fit=max&auto=format&n=SJlfH_n1UHSFJ8ir&q=85&s=be0b21eac3e9d991af600884df8c7eb6" alt="Normal vs Stealth" width="720" height="230" data-path="assets/diagrams/stealth-comparison.svg" />

## Key Concepts

### Stealth Meta-Address

A stealth meta-address is what you publish or share. It contains two public keys:

```
st:eth:0x{spendingPubKey}{viewingPubKey}
```

* **Spending public key** — used to derive stealth addresses. The private key lets you spend.
* **Viewing public key** — used to detect incoming payments. The private key lets you scan.

This two-key design means you can give a third party the viewing key to detect payments on your behalf without giving them the ability to spend.

### How a Payment Works

<img src="https://mintcdn.com/truth/SJlfH_n1UHSFJ8ir/assets/diagrams/stealth-flow.svg?fit=max&auto=format&n=SJlfH_n1UHSFJ8ir&q=85&s=8f747467d3fbf1ab29d812afb863fad6" alt="Stealth Payment Flow" width="720" height="130" data-path="assets/diagrams/stealth-flow.svg" />

**Step 1: Sender generates a stealth address**

```typescript theme={null}
import { generateStealthAddress } from "@wraith-protocol/sdk/chains/evm";

const { stealthAddress, ephemeralPubKey, viewTag } = generateStealthAddress(
  recipientSpendingPubKey,
  recipientViewingPubKey
);
// stealthAddress: fresh one-time address
// ephemeralPubKey: publish on-chain
// viewTag: publish on-chain (1 byte for fast filtering)
```

The sender:

1. Generates a random ephemeral key pair `(r, R)`
2. Computes a shared secret `S = r * viewingPubKey` (ECDH)
3. Hashes the secret: `h = hash(S)`
4. Computes stealth address = `spendingPubKey + h * G`
5. Sends funds to the stealth address
6. Publishes announcement: `(R, viewTag)`

**Step 2: Announcement**

The sender publishes an on-chain announcement containing the ephemeral public key `R` and a view tag. This is public, but reveals nothing about who the recipient is.

**Step 3: Recipient scans for payments**

```typescript theme={null}
import { scanAnnouncements } from "@wraith-protocol/sdk/chains/evm";

const matched = scanAnnouncements(
  announcements,
  keys.viewingKey,
  keys.spendingPubKey,
  keys.spendingKey
);
// matched: announcements that belong to you, with private keys
```

The recipient checks each announcement:

1. Compute shared secret `S = viewingKey * R` (same ECDH, other side)
2. Check view tag — if it doesn't match, skip (rejects \~255/256 non-matches)
3. Compute expected address = `spendingPubKey + hash(S) * G`
4. If expected address matches announced address, it's yours

**Step 4: Recipient spends**

```typescript theme={null}
import { deriveStealthPrivateKey } from "@wraith-protocol/sdk/chains/evm";

const privateKey = deriveStealthPrivateKey(
  keys.spendingKey,
  ephemeralPubKey,
  keys.viewingKey
);
// privateKey controls the stealth address
```

The private key: `stealthPrivateKey = spendingKey + hash(sharedSecret) mod n`

## View Tags: Fast Filtering

Without view tags, scanning requires a full ECDH computation + point addition for every announcement. View tags add a 1-byte shortcut:

```
With 1000 announcements:
  Without view tags: 1000 full checks
  With view tags:    1000 byte comparisons + ~4 full checks
```

The view tag eliminates \~255/256 non-matching announcements with a single byte comparison.

## EVM vs. Stellar

The same concept works on both chains, adapted to their cryptographic primitives:

| Step           | EVM (secp256k1)                              | Stellar (ed25519)                        |
| -------------- | -------------------------------------------- | ---------------------------------------- |
| Key derivation | `keccak256(r)`, `keccak256(s)` of wallet sig | `SHA-256("wraith:spending:" \|\| sig)`   |
| ECDH           | `secp256k1.getSharedSecret`                  | X25519 (Montgomery form)                 |
| Hash to scalar | `keccak256(S) mod n`                         | `SHA-256("wraith:scalar:" \|\| S) mod L` |
| View tag       | `keccak256(S)[0]`                            | `SHA-256("wraith:tag:" \|\| S)[0]`       |
| Address format | `0x...` (20 bytes)                           | `G...` (56 chars)                        |
| Signing        | secp256k1 ECDSA                              | ed25519 with raw scalar                  |

## Standards

EVM stealth addresses are based on:

* **ERC-5564** — Stealth Address Messenger (announcement format)
* **ERC-6538** — Stealth Meta-Address Registry (meta-address storage)

Wraith extends these with:

* **WraithNames** — human-readable `.wraith` name to meta-address mapping
* **WraithSender** — atomic send + announce in one transaction
* **WraithWithdrawer** — gas-sponsored withdrawals via EIP-7702

## Visual Flow

<img src="https://mintcdn.com/truth/RP_u3AwFnAKMgBKu/assets/diagrams/stealth-visual-flow.svg?fit=max&auto=format&n=RP_u3AwFnAKMgBKu&q=85&s=4f813361e1e0f1e71dc6f28f8d427d03" alt="Stealth Payment Full Flow" width="600" height="680" data-path="assets/diagrams/stealth-visual-flow.svg" />

## Using the Managed Agent

With the Wraith agent, all of this is handled automatically:

```typescript theme={null}
import { Wraith, Chain } from "@wraith-protocol/sdk";

const wraith = new Wraith({ apiKey: "wraith_..." });

const agent = await wraith.createAgent({
  name: "alice",
  chain: Chain.Horizen,
  wallet: "0x...",
  signature: "0x...",
});

// Sending handles stealth address generation + announcement
await agent.chat("send 0.1 ETH to bob.wraith");

// Scanning handles announcement detection + key derivation
await agent.chat("scan for payments");

// Withdrawing handles private key derivation + transaction signing
await agent.chat("withdraw all to 0xMyWallet");
```
