The implementation of that white paper formula is actually P = Hs(8rA || i)G+B
.
The 8
is there to force the rA
EC point to be in the group of the base point G, even when A
is a malicious point which is not in the base point group (i.e. is not a multiple of G).
The ||
symbol means byte concatenation, i.e. concatenate the bytes of the compressed representation of the EC point 8rA
with a varint byte representation of the output index i
. The output index is appended so that multiple outputs to the same recipient won't have identical public keys (which would be a disaster, because then they'd also share the same key image and only one of them would be able to be spent).
On this line you'll see a call to generate_key_derivation
: https://github.com/monero-project/monero/blob/102a51bcd48a3cd2cb794aab7dbe243393f155b3/src/cryptonote_core/cryptonote_tx_utils.cpp#L393
The generate_key_derivation
method calculates the 8rA
part using ge_scalarmult
to calculate the rA
part and using ge_mul8
to turn that into 8rA
.
On this line you'll see a call to derive_public_key
https://github.com/monero-project/monero/blob/102a51bcd48a3cd2cb794aab7dbe243393f155b3/src/cryptonote_core/cryptonote_tx_utils.cpp#L408
The derive_public_key
method takes the already calculated 8rA
, uses the derivation_to_scalar
method (which in turn uses the hash_to_scalar
method) to produce Hs(8rA || i)
, and then uses ge_scalarmult_base
to multiply it by G
to get Hs(8rA || i)G
. Finally it adds B
to get the final result Hs(8rA || i)G+B
.
You'll see some confusing methods like ge_p3_to_cached
and ge_p1p1_to_p2
etc. This is because the most efficient way of performing different operations on EC points is to convert them into different representations prior to particular operations. For more information, see "Faster Addition and Doubling on
Elliptic Curves" https://cr.yp.to/talks/2007.12.03/slides.pdf