Protocol Flow
From payment to spendable funds
The protocol has six stages. Each one exists to separate public discovery from private ownership while keeping the result usable in today's wallets.
Stage 1: Generate your keys
The backend generates two ML-KEM-768 keypairs:
- Spending keypair (
spending_pk/spending_sk) - determines where money lands - Viewing keypair (
viewing_pk/viewing_sk) - lets you find your payments
These are bundled into your meta-address: the public-facing profile that senders use.
curl -s -X POST https://backend.specterpq.com/api/v1/keys/generate | jq .
Response includes meta_address, spending_pk, spending_sk, viewing_pk, viewing_sk.

Stage 2: Publish your meta-address
Make your meta-address discoverable. Two options:
ENS (Ethereum): Upload meta-address to IPFS, set your ENS text record to point at the IPFS CID. Senders resolve alice.eth to your meta-address automatically.
SuiNS (Sui): Same pattern with Sui name records.
Or just share the raw meta-address string directly. Name services are convenient, not required.
Stage 3: Sender creates the payment
This is where ML-KEM does its work. The sender:
- Reads your
viewing_pkfrom the meta-address - Runs ML-KEM encapsulation to produce:
- A ciphertext (1,088 bytes) - this is the encrypted hint
- A shared secret (32 bytes) - known to both sender and recipient
- Computes a 1-byte view tag from the shared secret
- Derives a stealth address (Ethereum and/or Sui) from the shared secret + your
spending_pk
curl -s -X POST https://backend.specterpq.com/api/v1/stealth/create \
-H "Content-Type: application/json" \
-d '{"meta_address":"<RECIPIENT_META_ADDRESS>"}' | jq .
The sender then sends ETH/tokens to the returned stealth_address.

Stage 4: Sender posts an announcement
The announcement is the public breadcrumb. It contains:
| Field | Purpose |
|---|---|
ephemeral_key | The ML-KEM ciphertext (encrypted shared secret) |
view_tag | 1-byte filter for fast scanning |
tx_hash | Transaction reference (optional) |
amount | Payment amount (optional) |
chain | Target chain (optional) |
channel_id | Yellow channel link (optional) |
curl -s -X POST https://backend.specterpq.com/api/v1/registry/announcements \
-H "Content-Type: application/json" \
-d '{
"ephemeral_key":"<HEX_CIPHERTEXT>",
"view_tag":42,
"tx_hash":"0x...",
"amount":"0.1",
"chain":"ethereum"
}' | jq .
Stage 5: Recipient scans
This is the discovery process. The recipient:
- Loads announcements from the registry
- For each announcement, decapsulates the ciphertext using
viewing_sk - Computes the expected view tag from the shared secret
- Fast path: if the view tag doesn't match, skip (filters ~99.6% of announcements)
- Full path: if it matches, derive the stealth address and compare
curl -s -X POST https://backend.specterpq.com/api/v1/stealth/scan \
-H "Content-Type: application/json" \
-d '{
"viewing_sk":"<HEX>",
"spending_pk":"<HEX>",
"spending_sk":"<HEX>"
}' | jq .

Stage 6: Spend the funds
The scan returns everything needed to spend:
| Field | What it is |
|---|---|
stealth_address | The Ethereum address holding the funds |
stealth_sui_address | The Sui address (if applicable) |
eth_private_key | The derived private key for spending |
Import the private key into any Ethereum wallet and spend normally.
The scan response contains wallet secret material (eth_private_key, stealth_sk). Treat it like a seed phrase. Never log it, never expose it in analytics.
The three objects that matter
| Object | What it does | Who holds it |
|---|---|---|
| Meta-address | Public receiving profile | Published by recipient, read by senders |
| Announcement | Encrypted breadcrumb for discovery | Published by sender, scanned by recipient |
| Stealth private key | Controls the funds | Only the recipient |
What sender and recipient each see
- Sender's perspective
- Recipient's perspective
- Observer's perspective
The sender needs only the recipient's meta-address or name.
They never learn the recipient's real wallet address. They derive a fresh stealth address, send funds to it, and post an announcement. From their side, it's three API calls.
The recipient periodically scans the announcement registry with their viewing key.
When they find a match, they recover the private key for that stealth address and can spend the funds whenever they want. The scanning process takes 1-2 seconds for 100k announcements.
An observer sees a payment to a random-looking address and an announcement in the registry.
Without the recipient's viewing key, they can't determine who the payment is for. The ML-KEM ciphertext in the announcement is quantum-resistant.
The security split
The receiving path (stages 1-5) uses ML-KEM-768 and is post-quantum safe.
The spending path (stage 6) produces a secp256k1 key for Ethereum wallet compatibility. That part is classical.
Read Security Boundaries for why this split exists and how it could be resolved.