# Stealth Addresses
Transacting on the MWEB happens via stealth addresses. Stealth addresses are supported using the *Dual-Key Stealth Address Protocol (DKSAP)*. These addresses consist of 2 secp256k1 public keys (**Ai**, **Bi**) where **Ai** is the scan pubkey used for identifying outputs, and **Bi** is the spend pubkey.
### Notation
* **G** = Curve generator point
* Bold uppercase letter (**A**, **Ai**, etc.) represents a secp256k1 public key
* Bold lowercase letter (**a**, **ai**, etc.) represents a scalar
* A letter in single quotes ('K') represents the ASCII value of the character literal
* HASH32(x | y | z) represents the standard 32-byte `BLAKE3` hash of the conjoined serializations of `x`, `y`, and `z`
* HASH64(m) represents the `BLAKE3` hash of `m` using a 64-byte output digest
* SWITCH(**v**, **r**) represents the pedersen commitment generated using a blind switch with value **v** and key **r**.
### Address Generation
Unique stealth addresses should be generated deterministically from a wallet's seed using the following formula (using **G** = generator point):
1. Generate master scan keypair (**a**, **A**) using HD keychain path `m/1/0/100'`
2. Generate master spend keypair (**b**, **B**) using HD keychain path `m/1/0/101'`
3. Choose the lowest unused address index **i**
4. Calculate one-time spend keypair (**bi**, **Bi**) as:
**bi** = **b** + HASH32(**A** | **i** | **a**)
**Bi** = **bi\*G** where **G** refers to the curve generator point
5. Calculate one-time scan keypair (**ai**, **Ai**) as:
**ai** = **a\*bi**
**Ai** = **ai\*G** where **G** refers to the curve generator point
### Outputs
Outputs consist of the following data:
* **Co** - The pedersen commitment to the value.
* Output message, **m**, consisting of:
* **Ko** - The receiver's one-time public key.
* **Ke** - The key exchange public key.
* **Ks** - The sender's public key.
* **t** - The view tag. This is the first byte of the shared secret.
* **v'** - The masked value.
* **n'** - The masked nonce.
* A signature of the **m** using the sender's key **ks**.
* A rangeproof of **Co** that also commits to the **m**.
### Output Construction
To create an output for value **v** to a receiver's stealth address (**Ai**,**Bi**):
1. Generate a random sender keypair (**ks**, **Ks**). # TODO: Can we generate this deterministically?
2. Derive the nonce **n** as the first 16 bytes of HASH32('N'|**ks**)
3. Derive the sending key **s** = HASH32('S'|**Ai**|**Bi**|**v**|**n**)
4. Derive the shared secret **e** = HASH32('D'|**s*Ai**). The view tag **t** is the first byte of **e**.
5. Calculate the receiver's one-time public key **Ko** = **Bi** + HASH32('O'|**e**)***G**
6. Calculate the key exchange pubkey **Ke** = **s*Bi**
7. Derive the 64-byte mask **m** = HASH64(**e**)
8. Encrypt the value using **v'** = **v** ⊕ **m[32,39]**
9. Encrypt the nonce using **n'** = **n** ⊕ **m[40,55]**
10. Calculate the commitment **Co** = SWITCH(**v**, **m[0,31]**).
11. Generate the rangeproof for **Co**, committing also to **m**.
12. Sign **m** using the sender key **ks**.
### Output Identification
NOTE: the wallet must keep a map **Bi**->**i** of all used spend pubkeys and the next few unused ones.
To check if an output belongs to a wallet:
1. Calculate the ECDHE shared secret **e** = HASH32('D'|**a*Ke**)
2. If the first byte of **e** does not match the view tag **t**, the output does not belong to the wallet.
3. Calculate the one-time spend pubkey: **Bi** = **Ko** - HASH('O'|**e**)***G**
4. Lookup the index **i** that generates **Bi** from the wallet's map **Bi**->**i**. If not found, the output does not belong to the wallet.
5. Derive the 64-byte mask **m** = HASH64(**e**)
6. Decrypt the value **v** = **v'** ⊕ **m[32,39]** where **m[32,39]** refers to bytes 32-39 (0-based big-endian) of the 64 byte mask **m**.
7. Verify that SWITCH(**v**,**m[0-31]**) ?= **Co**
8. Decrypt the nonce **n** = **n'** ⊕ **m[40,55]**.
9. Calculate the send key **s** = HASH32('S'|**Ai**|**Bi**|**v**|**n**)
10. Verify that **Ke** ?= **s*Bi**.
If all verifications succeed, the output belongs to the wallet, and is safe to use.
The spend key can be recovered by **ko** = HASH32('O'|**e**) + **ai**.