Ring signatures alone would allow double spending, so Monero (as a result of following the CrpytoNote whitepaper) has to use a 'key image', which is the same across identical transactions and hence causes attempts at double spending to be rejected.

The key image is formed I = x*H(P), with I the key image, x the private key, H a deterministic hash function, and P a ephemeral public key for use in this transaction only.

My question is, in Monero's specific case, what hashing algorithm does H represent?


Looking at the code, we can see how it's generated.

void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
    ge_p3 point;
    ge_p2 point2;
    assert(sc_check(&sec) == 0);
    hash_to_ec(pub, point);
    ge_scalarmult(&point2, &sec, &point);
    ge_tobytes(&image, &point2);

The hash_to_ec function is called to hash pub (which is your P) into point, giving us your H(P). Then, scalar multiplication is performed and result passed into point2, which would be your x*H(P). Some transfromation ge_tobytes is applied and the result is passed into image which is your I.

I'm not sure what this ge_tobytes transformation does, though. It could be just changing the format of I in memory. Implementation specific, I suppose.

The hash_to_ec function is presented below.

static void hash_to_ec(const public_key &key, ge_p3 &res) {
    hash h;
    ge_p2 point;
    ge_p1p1 point2;
    cn_fast_hash(std::addressof(key), sizeof(public_key), h);
    ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h));
    ge_mul8(&point2, &point);
    ge_p1p1_to_p3(&res, &point2);

We see that the cn_fast_hash function is called, which would be the Keccak hash function. After getting the hash h, it is passed through some functions, which I suspect perform scalar multiplication of h with something, but my understanding stops here. This ge_fromfe_frombytes_vartime might be of interest as Shen Noether did a dedicated write-up on it. Also, here we see the importance of using a secure hash function for the key images. Apparently, to do this something after the Keccak is quite important.

Shen Noether's implementation in Python could provide some insights as well, but I'm not sure if it's up to date.

  • Thanks so much! I think ge_tobytes means group element to bytes, so it's just typecasting the input from a group element (or more specifically an elliptic curve point) to a byte array. Thanks again :) – bekah Nov 25 '16 at 23:00
  • 1
    @bekah No problem at all! Fyi, I've bumped into something regarding ge_fromfe... which might be of interest as well. Updated the answer. – JollyMort Nov 26 '16 at 9:58
  • 1
    See Signature, step 1, Section 3.3 of github.com/kurtmagnus/Monero-RCT-report/blob/master/main.pdf It's essentially private key * Hash_p(public key) (Hash_p is a hash function that returns an EC point) – Kurt M. Mar 7 '18 at 22:52

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.