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
xormask = amount_hs[: len(output.encamount)]
print(" xormask = {:s}".format(binascii.hexlify(xormask).decode()))
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
Receiving subaddress: 7ACPcxXBfZaPTsfzMXGKYyfhjcQXQYsTYhEfRx4qTb1fJDgK6EHHVHr47PSYpgMAzY1Vza6C7EcF5JQWV1PVckxTBd1CeVc
secret view key: e507923516f52389eae889b6edc182ada82bb9354fb405abedbe0772a15aea0a
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
xormask = e3b6b0fbaa7a5d28
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
Receiving subaddress: 79X56BnG8Ji4G7yCeVvrhvJHbbTyf8Y7XHGo7TUvwJRbjhyDcQM36Na7mkyS33S6WpaFt1WKHuq9AQXotpFbhSC3RZEnNV3
secret view key: e507923516f52389eae889b6edc182ada82bb9354fb405abedbe0772a15aea0a
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
xormask = 2c3fbf97e7afe8a9
dec_amount = dd35f66908899b4a
int_amount = 5376041249427305949
amount = 5376041.249427305949
The real amount here is 3.141592653523
but for some reason 5376041.249427305949
appears.