I am using monero-nodejs liberary for rpc calls. I generated an integrated address and made a payment to this address.

By splitting the integrated address, I could see the paymentId is a33582a5a77c125b.

But when I check payments of this address, I get nothing (empty object)


Do I need any decoding on this paymentId? I can see the tx mined.

  • 1
    Integrated payment IDs are encrypted. I don't know how to decrypt it however, but some advanced users might help. – el00ruobuob Aug 22 '18 at 6:49
  • I think I should change the title :) – Prashant Prabhakar Singh Aug 22 '18 at 6:52
  • @knaccc If you can help? – Prashant Prabhakar Singh Aug 22 '18 at 7:46
  • The payment id is stored in the tx_extra part of the transaction. To decode it you need to extract it, and then XOR it with (8a*R||0x8d) where a is your private view key, R is the transaction public key (which is also in tx_extra), || means concatenation, and * means elliptic curve scalar multiplication. I'm not familiar with this library, it looks like the maintainer will need to add this functionality. – knaccc Aug 22 '18 at 11:14
  • So everyone using this integrated address is using this complex maths to check if they received paymets correspoing to an integarted address? – Prashant Prabhakar Singh Aug 22 '18 at 12:42

MyMonero provides a useful JavaScript library (mymonero-core-js) for dealing with this sort of thing.

Here is a code snippet that shows how to encrypt/decrypt a payment id using this bit of code from mymonero-core-js.

const mm = require('mymonero-core-js').monero_utils

const viewKey = mm.random_keypair()
const txKey = mm.random_keypair()
const paymentId = 'badc0ffeefabcafe'


// If you have the private tx key and public view key
const pidKey = mm.cn_fast_hash(
  mm.generate_key_derivation(viewKey.pub, txKey.sec) +
).slice(0, INTEGRATED_ID_SIZE * 2)

// If you have the private view key and public tx key
const pidKey2 = mm.cn_fast_hash(
  mm.generate_key_derivation(txKey.pub, viewKey.sec) +
).slice(0, INTEGRATED_ID_SIZE * 2)

// Assert that the pidKeys are equal
console.log((pidKey === pidKey2)
  ? 'pidKeys are equal (expected)'
  : 'pidKeys are not equal (unexpected)')

// Encrypt Payment ID
const encryptedPaymentId = mm.hex_xor(paymentId, pidKey)
console.log('Encrypted: ' + encryptedPaymentId)

// Decrypt Payment ID
const decryptedPaymentId = mm.hex_xor(encryptedPaymentId, pidKey)
console.log('Decrypted: ' + decryptedPaymentId)

// Assert that the original and decrypted payment ids are equal
console.log((decryptedPaymentId === paymentId)
  ? 'Successful Decryption!'
  : 'Unsuccessful Decryption')

Should provide an output similar to:

pidKeys are equal (expected)
Encrypted: cfc3f2120b7db7c0
Decrypted: badc0ffeefabcafe
Successful Decryption!

Hope this helps!

  • Thanks. But I can see I get the same payment Id that I provided. I have encrypted payment Id , and I wish to decrypt it. Also, both encrypted and decrypted keys are of same length. But encrypted payment id is 16 chars where normal Payment ids is 106 chars. – Prashant Prabhakar Singh Aug 23 '18 at 6:38
  • No, payment IDs are either 32 bytes (64 hexadecimal characters) or 8 bytes (in the case of integrated addresses). As you asked about integrated addresses, the payment ID would be 8 bytes (or 16 chars as hex). There is no case where "Payment ids is 106 chars", whether encrypted, integrated, whatever. – jtgrassie Aug 23 '18 at 13:53

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.