What you'll learn
- What a stealth address actually is — and why publishing one is safe
- How to generate one with
getnewstealthaddress - How sending works under the hood (DKSAP — Dual-Key Stealth Address Protocol)
- How to scan for incoming payments
- How to verify the consensus-required OP_RETURN marker
DoS(100).
Background: the DKSAP protocol
Each stealth address holds two keypairs: a scan key (lets the wallet detect incoming payments) and a spend key (lets you actually move the coins). When Bob pays Alice's stealth address:
- Bob generates a random ephemeral keypair
(r, R = r·G) - Bob computes a shared secret
S = SHA256(ECDH(r, Alice_scan_pubkey)) - Bob derives a one-time destination
dest = Alice_spend_pubkey + SHA256(S)·G - Bob pays
Hash160(dest)— an address that has never appeared on chain before - Bob attaches
Ras a 35-byte OP_RETURN so Alice can find the payment
Every payment to the same stealth address lands on a different destination. An observer cannot link any two payments together.
Step-by-step
-
Generate a stealth address
$ MaryJaneCoind getnewstealthaddress "main" 8m9bqV3BiMkaajrYh7M9JwsS15b345x2idX7x6xYQfp26QnBBjNiu FM9q4twkYATeec953ydtZwiVgajqdLe8tESXUMP6nAJAThis is the address you publish. It encodes
version_byte(0x28) + scan_pubkey(33B) + spend_pubkey(33B) + checksum. -
Confirm the keypairs
$ MaryJaneCoind liststealthaddresses [ { "label": "main", "address": "8m9bqV3Bi...", "scan_pubkey": "0228721ba88c871ec...", "spend_pubkey": "021a485c18deb33c8d..." } ] -
Send to a stealth address
$ MaryJaneCoind sendtostealthaddress "8m9bqV3Bi..." 100.0 "a1b2c3d4e5f6..." # Regular sendtoaddress will also auto-detect stealth and route via DKSAP # (stealthmandatory=1 is the default once block 1,000 is reached) -
Scan for incoming payments
$ MaryJaneCoind scanstealthpayments 3 # found 3 payments to your stealth addressesThe wallet walks every TX it has seen, tries the ECDH unlock with each of your scan keys, and if the derived destination matches an output it adds the payment to your balance.
-
Inspect the on-chain structure
Output 0: 100.00000000 MARYJ → [one-time P2PKH] (payment) Output 1: 49.58000000 MARYJ → [change address] (change) Output 2: 0.00000000 MARYJ → OP_RETURN [33B R] (stealth marker)The marker is exactly
0x6a 0x21 [33-byte ephemeral pubkey]— 35 bytes total. Without it, validators reject the block.
How to verify it's working
- Run
getinfoand confirmstealth_mandatorymatches the chain height - Look up your TX in the explorer — the destination address should not match your published stealth string
- Send the same stealth address two payments and confirm two different destinations on chain