Subaddresses
Any number of unlinkable addresses from one key pair
The subaddress with index (i, j) is the pair of points D = B + m·G and C = a·D, where m = Hs("SubAddr\0" ‖ a ‖ i ‖ j). Without the view key a, you can't tell that subaddresses belong to the same wallet.
Why
If you gave one address to two different people, they can compare notes and realise they paid the same recipient. Subaddresses fix this: one address per payer, while the wallet stays one and scanning doesn't get slower.
Subaddresses form a two-level hierarchy: the account i (major) and the index within the account j (minor). Subaddress (0, 0) is the main address.
A wallet has exactly one main address — (0,0), which is just B and A with prefix 18. Any other index, including the "first" address of the second account (1,0), is a subaddress: its keys are derived via m = Hs("SubAddr\0" ‖ a ‖ 1 ‖ 0), and it's encoded with prefix 42, hence 8…. An account is just a way to group subaddresses; it has no "main" address of its own.
How it's computed
D = B + m·G C = a·D i and j are 32-bit little-endian numbers; "SubAddr\0" is 8 bytes with a trailing zero byte
A subaddress is encoded like a normal address but with prefix 42 (starts with 8 on mainnet): Base58(42 ‖ D ‖ C ‖ checksum).
Note that the subaddress's public "view key" C is not a·G but a·D. This trick is needed for sending.
Sending to a subaddress
When sending to a normal address the transaction key is R = r·G. When sending to a subaddress, the sender uses R = r·D. Then the recipient computes the shared secret as usual:
The sender knows r and C, the recipient knows a and R, and both get the same point.
How the wallet recognises its subaddresses
The wallet precomputes D for a few hundred indices and keeps a table D → (i, j). For each output it computes a candidate
and looks D' up in the table. Found it — the output is ours, and we know which subaddress it came to. That's why subaddresses don't slow scanning down: one subtraction and a hash-table lookup.
If a transaction has an output to a subaddress, the sending wallet uses a separate transaction key per output (additional keys in tx_extra). Otherwise the recipient could test whether the sender's change belongs to some address.