# How to decrypt the amounts properly?

I'm trying to decode outputs of transactions using the general algorithm described here. It flawlessly identifies my outputs, which proves I properly extract keys from `extra` and calculate valid `Hs(8aR||i)`, but then I have strange errors with amount decryption.

Most puzzling is that it actually works in some cases, while for most transactions it generates garbled data. Given the simplicity of operation (hash and xor) either I make some stupid mistake or I get invalid amount data from the transaction.

I looked into Monero source code and it seems I don't miss anything in the algorithm.

Here's my Python code snippet enriched with tons of debug prints. Please note I skipped the part of output identification, because it works.

``````print("    Hs         = {:s}".format(binascii.hexlify(Hs).decode()))    # Hs is Hs(8aR||i)
amount_hs = sha3.keccak_256(b"amount" + Hs).digest()
print("    amount_hs  = {:s}".format(binascii.hexlify(amount_hs).decode()))
print(
"    enc_amount = {:s}".format(
binascii.hexlify(output.encamount).decode()
)
)    # encamount is tx["rct_signatures"]["ecdhInfo"][oidx]["amount"]

# HERE THE PROBLEMS BEGIN

dec_amount = bytes(a ^ b for a, b in zip(output.encamount, xormask))
print("    dec_amount = {:s}".format(binascii.hexlify(dec_amount).decode()))
int_amount = int.from_bytes(
dec_amount, byteorder="little", signed=False
)
print("    int_amount = {:d}".format(int_amount))
amount = monero.numbers.from_atomic(int_amount)
print("    amount     = {:.12f}".format(amount))
``````

An example of transaction that passes properly: f4a11b4b3fb38f737d9cdcc088cd11b00379c4106b4e85132c2a8eeea41febfa:

``````Wallet master address: 56eDKfprZtQGfB4y6gVLZx5naKVHw6KEKLDoq2WWtLng9ANuBvsw67wfqyhQECoLmjQN4cKAdvMp2WsC5fnw9seKLcCSfjj
checking tx: f4a11b4b3fb38f737d9cdcc088cd11b00379c4106b4e85132c2a8eeea41febfa
tx has   2 outputs
tx has   1 keys
checking output 0
checking key 0: 1bd7ed2b23b246e91450e0cf28bb0fed471dec68d222b0f65c79928df73d83df
Hs         = 52183965dafe3f7a77e5d544420a6fe6a1dcc9ab4a3d2a6a2559cf3639d31e09
amount_hs  = e3b6b0fbaa7a5d285133dbb985976230a89c07e8392f2cb2b5bf0ccecf814cfb
enc_amount = 2bb24b8ab57b5d28
dec_amount = c804fb711f010000
int_amount = 1234567890120
amount     = 1.234567890120
checking output 1
checking key 0: 1bd7ed2b23b246e91450e0cf28bb0fed471dec68d222b0f65c79928df73d83df
no match
``````

However, another one fails miserably: 5e149f7f97f55afb99ecdf7836bea6ef9a0e61202ffcd466300da56b2b083c00

``````Wallet master address: 56eDKfprZtQGfB4y6gVLZx5naKVHw6KEKLDoq2WWtLng9ANuBvsw67wfqyhQECoLmjQN4cKAdvMp2WsC5fnw9seKLcCSfjj
checking tx: 5e149f7f97f55afb99ecdf7836bea6ef9a0e61202ffcd466300da56b2b083c00
tx has   2 outputs
tx has   1 keys
checking output 0
checking key 0: 7a4521bc639bc4398bbbd07c89096348d70189a3f69593b248b2a7cd374dab1f
no match
checking output 1
checking key 0: 7a4521bc639bc4398bbbd07c89096348d70189a3f69593b248b2a7cd374dab1f
Hs         = 4e2918eb07facce065c1fcfe610a5b7d18064d64a7b8844d1844872f6d60159f
amount_hs  = 2c3fbf97e7afe8a91c1ea2366a781335cbfe2ae955f2c35e79c758f57bba4679
enc_amount = f10a49feef2673e3
dec_amount = dd35f66908899b4a
int_amount = 5376041249427305949
amount     = 5376041.249427305949
``````

The real amount here is `3.141592653523` but for some reason `5376041.249427305949` appears.

• You say it flawlessly identifies your outputs but your second example doesn't match output at index 0 but then does at index 1. If the tx is destined for you, every output key you should own? – jtgrassie Feb 3 '20 at 16:44
• Why should it match output 0? It's change and it belongs to the sender, not me. – emesik Feb 3 '20 at 22:56
• Ah, yes right, change. I wrongly assumed you were checking a tx where both outputs were owned by / sent to you. Props to @knaccc for spotting the missing reduce. – jtgrassie Feb 4 '20 at 2:02

The Hs value in your failing transaction is incorrect. You've written `4e2918eb07facce065c1fcfe610a5b7d18064d64a7b8844d1844872f6d60159f` but it should be `f9b573a61a7e27c8dc3d48448e4184c117064d64a7b8844d1844872f6d60150f`.
• @emesik It works because a `mod l` of that `Hs(8aR||i)` value automatically happens during scalar multiplication with `G`, because `l` is the same as the group size of `G`. You're lucky that your ed25519 library treats the out-of-bounds Hs number properly during that scalar multiplication. – knaccc Feb 4 '20 at 1:34
• Right! The recognition dramatically improved, but still fails sometimes. Is it possible that `sc_reduce32` does more than just modulo `l`? – emesik Feb 4 '20 at 11:17
• @emesik All sc_reduce32 does is `mod l`. If you have another example of a failing tranasction, please post it. It's possible you may be looking at an older transaction where amounts are 32 byte scalars and need to be decoded differently than 8 byte amounts. – knaccc Feb 4 '20 at 23:32