First note that in Monero there are two sets of keypairs, namely the private view key (a) (which is the private spend key hashed with Keccak-256 and subsequently reduced modulo l) with the corresponding public view key (
aG (G = the base point) = A) and the private spend key (b) with the corresponding public spend key (
bG (G = the base point) = B). The public address is then created as follows:
- The pair of public keys are prepended with one network byte (the number 18, 0x12, for Monero). It looks like this: (network byte) + (32-byte public spend key) + (32-byte public view key).
- These 65 bytes are hashed with Keccak-256.
- The first four bytes of the hash from 2. are appended to 1., creating a 69-byte Public Address.
- As a last step, this 69-byte string is converted to Base58. However, it's not done all at once like a Bitcoin address, but rather in 8-byte blocks. This gives us eight full-sized blocks and one 5-byte block. Eight bytes converts to 11 or less Base58 characters; if a particular block converts to <11 characters, the conversion pads it with "1"s (1 is 0 in Base58). Likewise, the final 5-byte block can convert to 7 or less Base58 digits; the conversion will ensure the result is 7 digits. Due to the conditional padding, the 69-byte string will always convert to 95 Base58 characters (8 * 11 + 7).
- This 95-character result is the (obscenely long) Cryptonote Public Address!
- If you're creating an integrated address, simply append the 64-bit payment ID to step 1 and continue; everything else is the same except for the lengths (77 bytes total, 106 Base58 digits) and the prepended byte (19, 0x13).
It logically follows that the addition of
B to the creation of a one-time public address (stealth address) is required in order for a user to be able to optionally disclose his public address + private view key. This allows a third-party (e.g. an auditor) to view all incoming transactions to the user's wallet without knowledge of their private spend key.
Lastly, a note from luigi1111 (a Monero core-team member) on single-key / non-dual key stealth addresses:
It is possible to do a non-dual-key stealth addressing scheme, but you must make one of two trade-offs. You can either: (1). use the concept in the whitepaper called a truncated address, which means the view key pair is publicly known and all incoming transactions can be linked (
a = Hs(B)); or (2). forego a view key pair entirely, which means scanning requires spending ability (
P = Hs(rB)G + B).