Compare commits

...

7 Commits

Author SHA1 Message Date
Michał Sałaban d24044a5e7 Add security update message
2 years ago
Michał Sałaban 8d473e7381 Bump up version
2 years ago
Michał Sałaban a64bef178f Add contributors
2 years ago
j-berman ece5b9d4cd Verify commitment == yG + bH
2 years ago
Michał Sałaban 00c0955989 Add tests on garbled ecdhInfo field
2 years ago
Michał Sałaban 3aac154dde Update black
2 years ago
Michał Sałaban da200d2f33 Update requirements
2 years ago

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 1.0.1 current_version = 1.0.2
parse = (?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))? parse = (?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?
serialize = serialize =
{major}.{minor}.{patch} {major}.{minor}.{patch}

@ -2,7 +2,7 @@ exclude:
^(build/|dist/|docs/|htmlcov/|venv/) ^(build/|dist/|docs/|htmlcov/|venv/)
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 21.11b1 rev: 22.3.0
hooks: hooks:
- id: black - id: black
language_version: python3 language_version: python3

@ -11,10 +11,16 @@ Python Monero module
.. |coveralls| image:: https://coveralls.io/repos/github/monero-ecosystem/monero-python/badge.svg .. |coveralls| image:: https://coveralls.io/repos/github/monero-ecosystem/monero-python/badge.svg
.. _coveralls: https://coveralls.io/github/monero-ecosystem/monero-python .. _coveralls: https://coveralls.io/github/monero-ecosystem/monero-python
.. warning:: **URGENT SECURITY UPDATE**
The version 1.0.2 contains an urgent security update in the output recognition code. If you're
using the module for scanning transactions and identifying outputs using the secret view key,
UPDATE THE SOFTWARE IMMEDIATELY.
Otherwise you're safe. Standard wallet operations like receiving payments, spending, address
generation etc. are NOT AFFECTED.
A comprehensive Python module for handling Monero cryptocurrency. A comprehensive Python module for handling Monero cryptocurrency.
* release 1.0.1 * release 1.0.2
* open source: https://github.com/monero-ecosystem/monero-python * open source: https://github.com/monero-ecosystem/monero-python
* works with Monero 0.17.x and `the latest source`_ (at least we try to keep up) * works with Monero 0.17.x and `the latest source`_ (at least we try to keep up)
* Python 2.x and 3.x compatible * Python 2.x and 3.x compatible
@ -37,7 +43,7 @@ Released under the BSD 3-Clause License. See `LICENSE.txt`_.
Copyright (c) 2017-2018 Michał Sałaban <michal@salaban.info> and Contributors: Copyright (c) 2017-2018 Michał Sałaban <michal@salaban.info> and Contributors:
`lalanza808`_, `cryptochangements34`_, `atward`_, `rooterkyberian`_, `brucexiu`_, `lalanza808`_, `cryptochangements34`_, `atward`_, `rooterkyberian`_, `brucexiu`_,
`lialsoftlab`_, `moneroexamples`_, `massanchik`_, `MrClottom`_, `jeffro256`_, `lialsoftlab`_, `moneroexamples`_, `massanchik`_, `MrClottom`_, `jeffro256`_,
`sometato`_. `sometato`_, `kayabaNerve`_, `j-berman`_.
Copyright (c) 2016 The MoneroPy Developers (``monero/base58.py`` taken from `MoneroPy`_) Copyright (c) 2016 The MoneroPy Developers (``monero/base58.py`` taken from `MoneroPy`_)
@ -58,6 +64,8 @@ Copyright (c) 2011 thomasv@gitorious (``monero/seed.py`` based on `Electrum`_)
.. _`MrClottom`: https://github.com/MrClottom .. _`MrClottom`: https://github.com/MrClottom
.. _`jeffro256`: https://github.com/jeffro256 .. _`jeffro256`: https://github.com/jeffro256
.. _`sometato`: https://github.com/sometato .. _`sometato`: https://github.com/sometato
.. _`kayabaNerve`: https://github.com/kayabaNerve
.. _`j-berman`: https://github.com/j-berman
Want to help? Want to help?
------------- -------------

@ -4,7 +4,7 @@ Authors
* Michał Sałaban <michal@salaban.info> * Michał Sałaban <michal@salaban.info>
* MoneroPy Developers (``monero/base58.py`` taken from `MoneroPy`_) * MoneroPy Developers (``monero/base58.py`` taken from `MoneroPy`_)
* thomasv@gitorious (``monero/seed.py`` based on `Electrum`_) * thomasv@gitorious (``monero/seed.py`` based on `Electrum`_)
* and other Contributors: `lalanza808`_, `cryptochangements34`_, `atward`_, `rooterkyberian`_, `brucexiu`_, `lialsoftlab`_, `moneroexamples`_, `massanchik`_, `MrClottom`_, `jeffro256`_, `sometato`_. * and other Contributors: `lalanza808`_, `cryptochangements34`_, `atward`_, `rooterkyberian`_, `brucexiu`_, `lialsoftlab`_, `moneroexamples`_, `massanchik`_, `MrClottom`_, `jeffro256`_, `sometato`_, `kayabaNerve`_, `j-berman`_.
.. _`LICENSE.txt`: LICENSE.txt .. _`LICENSE.txt`: LICENSE.txt
@ -22,6 +22,8 @@ Authors
.. _`MrClottom`: https://github.com/MrClottom .. _`MrClottom`: https://github.com/MrClottom
.. _`jeffro256`: https://github.com/jeffro256 .. _`jeffro256`: https://github.com/jeffro256
.. _`sometato`: https://github.com/sometato .. _`sometato`: https://github.com/sometato
.. _`kayabaNerve`: https://github.com/kayabaNerve
.. _`j-berman`: https://github.com/j-berman
Acknowledgements Acknowledgements
---------------- ----------------

@ -27,7 +27,7 @@ sys.path.insert(0, os.path.abspath("../.."))
# If your documentation needs a minimal Sphinx version, state it here. # If your documentation needs a minimal Sphinx version, state it here.
# #
# needs_sphinx = '1.0.1' # needs_sphinx = '1.0.2'
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@ -56,9 +56,9 @@ author = "Michal Salaban"
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = "1.0.1" version = "1.0.2"
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = "1.0.1" release = "1.0.2"
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

@ -3,6 +3,13 @@
Python module for Monero Python module for Monero
======================== ========================
.. warning:: **URGENT SECURITY UPDATE**
The version 1.0.2 contains an urgent security update in the output recognition code. If you're
using the module for scanning transactions and identifying outputs using the secret view key,
UPDATE THE SOFTWARE IMMEDIATELY.
Otherwise you're safe. Standard wallet operations like receiving payments, spending, address
generation etc. are NOT AFFECTED.
Welcome to the documentation for the ``monero`` Python module. Welcome to the documentation for the ``monero`` Python module.
The aim of this project is to offer a set of tools for interacting with Monero The aim of this project is to offer a set of tools for interacting with Monero

@ -1,3 +1,3 @@
from . import address, account, const, daemon, wallet, numbers, wordlists, seed from . import address, account, const, daemon, wallet, numbers, wordlists, seed
__version__ = "1.0.1" __version__ = "1.0.2"

@ -7,6 +7,15 @@ scalar_add = nacl.bindings.crypto_core_ed25519_scalar_add
scalarmult_B = nacl.bindings.crypto_scalarmult_ed25519_base_noclamp scalarmult_B = nacl.bindings.crypto_scalarmult_ed25519_base_noclamp
scalarmult = nacl.bindings.crypto_scalarmult_ed25519_noclamp scalarmult = nacl.bindings.crypto_scalarmult_ed25519_noclamp
# https://github.com/monero-project/monero/blob/9f814edbd78c70c70b814ca934c1ddef58768262/src/ringct/rctTypes.h#L615
H = binascii.unhexlify(
"8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
)
def scalarmult_H(v):
return scalarmult(v, H)
def scalar_reduce(v): def scalar_reduce(v):
return nacl.bindings.crypto_core_ed25519_scalar_reduce(v + (64 - len(v)) * b"\0") return nacl.bindings.crypto_core_ed25519_scalar_reduce(v + (64 - len(v)) * b"\0")

@ -140,7 +140,7 @@ class Transaction(object):
already generated. already generated.
""" """
def _scan_pubkeys(svk, psk, stealth_address, amount, encamount): def _scan_pubkeys(svk, psk, stealth_address, amount, encamount, commitment):
for keyidx, tx_key in enumerate(self.pubkeys): for keyidx, tx_key in enumerate(self.pubkeys):
# precompute # precompute
svk_2 = ed25519.scalar_add(svk, svk) svk_2 = ed25519.scalar_add(svk, svk)
@ -174,14 +174,22 @@ class Transaction(object):
dec_amount = bytearray( dec_amount = bytearray(
a ^ b for a, b in zip(*map(bytearray, (encamount, xormask))) a ^ b for a, b in zip(*map(bytearray, (encamount, xormask)))
) )
int_amount = struct.unpack("<Q", dec_amount)[0] # verify that the commitment == yG + bH
amount = from_atomic(int_amount) # https://web.getmonero.org/library/Zero-to-Monero-2-0-0.pdf#section.5.3
return Payment( y = ed25519.scalar_reduce(keccak_256(b"commitment_mask" + Hs).digest())
amount=amount, yG = ed25519.scalarmult_B(y)
timestamp=self.timestamp, b = ed25519.scalar_reduce(bytes(dec_amount))
transaction=self, bH = ed25519.scalarmult_H(b)
local_address=addr, amount = 0
) if commitment == ed25519.edwards_add(yG, bH):
int_amount = struct.unpack("<Q", dec_amount)[0]
amount = from_atomic(int_amount)
return Payment(
amount=amount,
timestamp=self.timestamp,
transaction=self,
local_address=addr,
)
if not self.json: if not self.json:
raise exceptions.TransactionWithoutJSON( raise exceptions.TransactionWithoutJSON(
@ -203,10 +211,14 @@ class Transaction(object):
for idx, vout in enumerate(self.json["vout"]): for idx, vout in enumerate(self.json["vout"]):
stealth_address = binascii.unhexlify(vout["target"]["key"]) stealth_address = binascii.unhexlify(vout["target"]["key"])
encamount = None encamount = None
commitment = None
if self.version == 2 and not self.is_coinbase: if self.version == 2 and not self.is_coinbase:
encamount = binascii.unhexlify( encamount = binascii.unhexlify(
self.json["rct_signatures"]["ecdhInfo"][idx]["amount"] self.json["rct_signatures"]["ecdhInfo"][idx]["amount"]
) )
commitment = binascii.unhexlify(
self.json["rct_signatures"]["outPk"][idx]
)
payment = None payment = None
amount = ( amount = (
from_atomic(vout["amount"]) from_atomic(vout["amount"])
@ -217,7 +229,7 @@ class Transaction(object):
for addridx, addr in enumerate(addresses): for addridx, addr in enumerate(addresses):
psk = binascii.unhexlify(addr.spend_key()) psk = binascii.unhexlify(addr.spend_key())
payment = _scan_pubkeys( payment = _scan_pubkeys(
svk, psk, stealth_address, amount, encamount svk, psk, stealth_address, amount, encamount, commitment
) )
if payment: if payment:
break break

@ -1,4 +1,4 @@
pycryptodomex~=3.10 pycryptodomex~=3.14
pynacl~=1.4 pynacl~=1.4
pysocks~=1.7 pysocks~=1.7
requests requests

@ -1,8 +1,8 @@
black==21.11b1 black~=22.3
coverage~=5.3 coverage~=6.3
coveralls~=2.1 coveralls~=3.3
pip>=9 pip>=9
pytest-cov~=2.10 pytest-cov~=3.0
pytest-runner~=5.2 pytest-runner~=5.2
pytest~=6.1 pytest~=7.1
responses~=0.12 responses~=0.20

@ -0,0 +1,30 @@
{
"credits": 0,
"status": "OK",
"top_hash": "",
"txs": [
{
"as_hex": "",
"as_json": "{\n \"version\": 2, \n \"unlock_time\": 0, \n \"vin\": [ {\n \"key\": {\n \"amount\": 0, \n \"key_offsets\": [ 4325102, 464564, 19546, 7828, 15534, 180, 1645, 763, 454, 2046, 9\n ], \n \"k_image\": \"235fa321338a6317a6064fc13b9917c5b9e36dc929b0d3f01d19a6ff9a1d9169\"\n }\n }\n ], \n \"vout\": [ {\n \"amount\": 0, \n \"target\": {\n \"key\": \"4cd1c255c3247d2c2324fb580dd66f1158acc0ba352a4bddf9bb5d724f2b9d4a\"\n }\n }, {\n \"amount\": 0, \n \"target\": {\n \"key\": \"72a976004da61eabbe7ef1f074ac1ad960347f18b63e79c0b4075c70c6faa71a\"\n }\n }\n ], \n \"extra\": [ 1, 147, 181, 21, 141, 147, 122, 16, 161, 230, 64, 52, 218, 173, 173, 125, 69, 35, 14, 168, 251, 151, 140, 33, 64, 2, 68, 15, 75, 31, 24, 59, 150, 2, 9, 1, 56, 181, 21, 158, 240, 73, 6, 247\n ], \n \"rct_signatures\": {\n \"type\": 5, \n \"txnFee\": 44760000, \n \"ecdhInfo\": [ {\n \"amount\": \"bb400d3177c30ab5\"\n }, {\n \"amount\": \"c284adb69f34912c\"\n }], \n \"outPk\": [ \"2b63045a7fc922e73eb74cf179ca1640f36ba97ce8f27137dc30ca8e407d99c1\", \"a25db81bcfaf13950d9a353c6c2a55f45e103fa91d3dadad19cb1087f425fa96\"]\n }\n}",
"block_height": 1079424,
"block_timestamp": 1650936396,
"double_spend_seen": false,
"in_pool": false,
"output_indices": [
4837766,
4837767
],
"prunable_as_hex": "",
"prunable_hash": "ab173d3c08a7251cfd9ca58c67345368828f6f5f1d92972b79d080489956c154",
"pruned_as_hex": "02000102000beefd8702b4ad1cda9801943dae79b401ed0cfb05c603fe0f09235fa321338a6317a6064fc13b9917c5b9e36dc929b0d3f01d19a6ff9a1d91690200024cd1c255c3247d2c2324fb580dd66f1158acc0ba352a4bddf9bb5d724f2b9d4a000272a976004da61eabbe7ef1f074ac1ad960347f18b63e79c0b4075c70c6faa71a2c0193b5158d937a10a1e64034daadad7d45230ea8fb978c214002440f4b1f183b9602090138b5159ef04906f705c0f7ab15bb400d3177c30ab5c284adb69f34912c2b63045a7fc922e73eb74cf179ca1640f36ba97ce8f27137dc30ca8e407d99c1a25db81bcfaf13950d9a353c6c2a55f45e103fa91d3dadad19cb1087f425fa96",
"tx_hash": "f7e60d07c8e201b779871e3817edf8388e6ea775922def5758aef231d3ced36a"
}
],
"txs_as_hex": [
""
],
"txs_as_json": [
"{\n \"version\": 2, \n \"unlock_time\": 0, \n \"vin\": [ {\n \"key\": {\n \"amount\": 0, \n \"key_offsets\": [ 4325102, 464564, 19546, 7828, 15534, 180, 1645, 763, 454, 2046, 9\n ], \n \"k_image\": \"235fa321338a6317a6064fc13b9917c5b9e36dc929b0d3f01d19a6ff9a1d9169\"\n }\n }\n ], \n \"vout\": [ {\n \"amount\": 0, \n \"target\": {\n \"key\": \"4cd1c255c3247d2c2324fb580dd66f1158acc0ba352a4bddf9bb5d724f2b9d4a\"\n }\n }, {\n \"amount\": 0, \n \"target\": {\n \"key\": \"72a976004da61eabbe7ef1f074ac1ad960347f18b63e79c0b4075c70c6faa71a\"\n }\n }\n ], \n \"extra\": [ 1, 147, 181, 21, 141, 147, 122, 16, 161, 230, 64, 52, 218, 173, 173, 125, 69, 35, 14, 168, 251, 151, 140, 33, 64, 2, 68, 15, 75, 31, 24, 59, 150, 2, 9, 1, 56, 181, 21, 158, 240, 73, 6, 247\n ], \n \"rct_signatures\": {\n \"type\": 5, \n \"txnFee\": 44760000, \n \"ecdhInfo\": [ {\n \"amount\": \"bb400d3177c30ab5\"\n }, {\n \"amount\": \"c284adb69f34912c\"\n }], \n \"outPk\": [ \"2b63045a7fc922e73eb74cf179ca1640f36ba97ce8f27137dc30ca8e407d99c1\", \"a25db81bcfaf13950d9a353c6c2a55f45e103fa91d3dadad19cb1087f425fa96\"]\n }\n}"
],
"untrusted": false
}

@ -0,0 +1,18 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"subaddress_accounts": [
{
"account_index": 0,
"balance": 11709717332048,
"base_address": "54LUsTyVL2haFdvkUVngGCiacaRYkjrUvfhvnF6JS2fXNL6twQUQf7PEPtf9MvRYXvhVmtzcV2MUefinDjjwVcH56xm3AHx",
"label": "Primary account",
"tag": "",
"unlocked_balance": 11709717332048
}
],
"total_balance": 11709717332048,
"total_unlocked_balance": 11709717332048
}
}

@ -0,0 +1,7 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"key": "a759f8631116a607e0d905c09c633e320825d3a05e2b5fc54ab5f812f01a1d04"
}
}

@ -0,0 +1,69 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"address": "54LUsTyVL2haFdvkUVngGCiacaRYkjrUvfhvnF6JS2fXNL6twQUQf7PEPtf9MvRYXvhVmtzcV2MUefinDjjwVcH56xm3AHx",
"addresses": [
{
"address": "54LUsTyVL2haFdvkUVngGCiacaRYkjrUvfhvnF6JS2fXNL6twQUQf7PEPtf9MvRYXvhVmtzcV2MUefinDjjwVcH56xm3AHx",
"address_index": 0,
"label": "Primary account",
"used": true
},
{
"address": "74fu2Uiveqg8XwxtLK4kdMPkCZNuW8gGC7nWgB8kJF1rACfbGvPKirrSaKFnxtUJePfnGTPRQ1Tp3jR2PKAavqQ7RNrsJbb",
"address_index": 1,
"label": "(Untitled address)",
"used": true
},
{
"address": "72KSFPEUK5MDvo716tgRrndsRgB3UtWczAXVBjqDZCvRitvUKKA8saNH9LCD1ExCM5VAKuZJTtnH495vEupxRn7EEYbUrGV",
"address_index": 2,
"label": "(Untitled address)",
"used": true
},
{
"address": "7As2Hf3RwGWSCJAPFFHXDyLg5qywN8MiqcmpWPiM3Mc7bmuoA1V78HWEf3GctXtveHSH35hk6NVGK7TAQoyXpy3ATvEYgPz",
"address_index": 3,
"label": "(Untitled address)",
"used": true
},
{
"address": "771dkwjPR1UDTMM7NVbJ6LDX2pQdBaHqDZKSzViPTDaxVjG7idfF9uP2i8xftcV1JfZYESDzvFvAUJ1ym89uPy7VQ9Nd9BA",
"address_index": 4,
"label": "(Untitled address)",
"used": true
},
{
"address": "798wHkYNUqc5UWYdeYiFmrYeXV7Rd23MqasV3YWAYLbeieYb3ogLEkB9TugZkP72qMMtnhxAuyr62P9GLk3Ai5EMS6mCTdu",
"address_index": 5,
"label": "(Untitled address)",
"used": true
},
{
"address": "7AVgqHzSLu227tv2HGvPAYcbVqTzbbNsAC99QpPZwZzudGsEypD4ZjrQQcansdaQGDLtUbdEhqHfeNjgEWPFAUoVGq1dnbE",
"address_index": 6,
"label": "(Untitled address)",
"used": true
},
{
"address": "77xBMPG3k5qEmQmreBbeqJYwcx9kkEz2y2abCFvRRrjKZVr2LVois3kGRM4kzXUqmj7PtTkiUza6rXnNZ5HM17pd2AbsVEA",
"address_index": 7,
"label": "(Untitled address)",
"used": true
},
{
"address": "72barfe7Sp9JZkyLCYLn3wfGhysUUQJqgJPp7DtjStjFdFUXR376ypzYKyxgMcXNE3AStjFmaSKAq6pv78jKPsbTTLq3uNb",
"address_index": 8,
"label": "(Untitled address)",
"used": true
},
{
"address": "77a1kZkpr9uZMD2kcunkE67JiNN6dZhXAUa6ACFtP8j4MqTipM1QW5FSLkeEJZ5jzaMYNauPcavyPMF2VCVr8i5XEFizNkv",
"address_index": 9,
"label": "(Untitled address)",
"used": false
}
]
}
}

@ -0,0 +1,30 @@
{
"credits": 0,
"status": "OK",
"top_hash": "",
"txs": [
{
"as_hex": "",
"as_json": "{\n \"version\": 2, \n \"unlock_time\": 0, \n \"vin\": [ {\n \"key\": {\n \"amount\": 0, \n \"key_offsets\": [ 4675357, 101625, 27510, 10864, 17256, 2990, 745, 369, 17, 654, 290\n ], \n \"k_image\": \"8d07ba16fd1bcc8eeb2fa485eb293baafe4a06f6096f948fedb6679606c7ea9c\"\n }\n }\n ], \n \"vout\": [ {\n \"amount\": 0, \n \"target\": {\n \"key\": \"5c09c39a189d1ceb7bceb1929a4fc676642d4277fdd3abaec2a3f7c0368e8077\"\n }\n }, {\n \"amount\": 0, \n \"target\": {\n \"key\": \"1a8b5aa09c1ccfb310ad913a6b577a7e723a53619fb4fd1d9b5e831fc1694be0\"\n }\n }\n ], \n \"extra\": [ 1, 65, 88, 164, 63, 169, 150, 146, 177, 47, 124, 96, 195, 68, 227, 158, 193, 234, 47, 182, 8, 160, 78, 94, 188, 2, 231, 225, 89, 49, 186, 237, 123, 2, 9, 1, 130, 171, 128, 151, 207, 6, 115, 252\n ], \n \"rct_signatures\": {\n \"type\": 5, \n \"txnFee\": 44790000, \n \"ecdhInfo\": [ {\n \"amount\": \"1ad451cc41a9baf7\"\n }, {\n \"amount\": \"0a6ded7a1104d184\"\n }], \n \"outPk\": [ \"9338cbbdc552ac770797da8af3a589b02e9ad5928d439875760d89dfae1de4ba\", \"05e5685aa757e6420ef889107c7d4c0fc64c698f8bbaa7192ba7164c88ce8b46\"]\n }\n}",
"block_height": 1079424,
"block_timestamp": 1650936396,
"double_spend_seen": false,
"in_pool": false,
"output_indices": [
4837768,
4837769
],
"prunable_as_hex": "",
"prunable_hash": "7c4eccf0c4f947280645e3aa18f250b90d8466bdedc9371bcca780321fa1e00b",
"pruned_as_hex": "02000102000b9dae9d02f99906f6d601f054e88601ae17e905f102118e05a2028d07ba16fd1bcc8eeb2fa485eb293baafe4a06f6096f948fedb6679606c7ea9c0200025c09c39a189d1ceb7bceb1929a4fc676642d4277fdd3abaec2a3f7c0368e807700021a8b5aa09c1ccfb310ad913a6b577a7e723a53619fb4fd1d9b5e831fc1694be02c014158a43fa99692b12f7c60c344e39ec1ea2fb608a04e5ebc02e7e15931baed7b02090182ab8097cf0673fc05f0e1ad151ad451cc41a9baf70a6ded7a1104d1849338cbbdc552ac770797da8af3a589b02e9ad5928d439875760d89dfae1de4ba05e5685aa757e6420ef889107c7d4c0fc64c698f8bbaa7192ba7164c88ce8b46",
"tx_hash": "54731f9263e92c9e249d8eb677f7c8f1c7edb9812092479f026062139842e0e0"
}
],
"txs_as_hex": [
""
],
"txs_as_json": [
"{\n \"version\": 2, \n \"unlock_time\": 0, \n \"vin\": [ {\n \"key\": {\n \"amount\": 0, \n \"key_offsets\": [ 4675357, 101625, 27510, 10864, 17256, 2990, 745, 369, 17, 654, 290\n ], \n \"k_image\": \"8d07ba16fd1bcc8eeb2fa485eb293baafe4a06f6096f948fedb6679606c7ea9c\"\n }\n }\n ], \n \"vout\": [ {\n \"amount\": 0, \n \"target\": {\n \"key\": \"5c09c39a189d1ceb7bceb1929a4fc676642d4277fdd3abaec2a3f7c0368e8077\"\n }\n }, {\n \"amount\": 0, \n \"target\": {\n \"key\": \"1a8b5aa09c1ccfb310ad913a6b577a7e723a53619fb4fd1d9b5e831fc1694be0\"\n }\n }\n ], \n \"extra\": [ 1, 65, 88, 164, 63, 169, 150, 146, 177, 47, 124, 96, 195, 68, 227, 158, 193, 234, 47, 182, 8, 160, 78, 94, 188, 2, 231, 225, 89, 49, 186, 237, 123, 2, 9, 1, 130, 171, 128, 151, 207, 6, 115, 252\n ], \n \"rct_signatures\": {\n \"type\": 5, \n \"txnFee\": 44790000, \n \"ecdhInfo\": [ {\n \"amount\": \"1ad451cc41a9baf7\"\n }, {\n \"amount\": \"0a6ded7a1104d184\"\n }], \n \"outPk\": [ \"9338cbbdc552ac770797da8af3a589b02e9ad5928d439875760d89dfae1de4ba\", \"05e5685aa757e6420ef889107c7d4c0fc64c698f8bbaa7192ba7164c88ce8b46\"]\n }\n}"
],
"untrusted": false
}

@ -0,0 +1 @@
test_v2_single_output_with_fake_amount_to_master-wallet-00-get_accounts.json

@ -0,0 +1 @@
test_v2_single_output_with_fake_amount_to_master-wallet-01-query_key.json

@ -0,0 +1 @@
test_v2_single_output_with_fake_amount_to_master-wallet-02-addresses-account-0.json

@ -157,6 +157,108 @@ class OutputTestCase(JSONTestCase):
"to [76Qt2x]", "to [76Qt2x]",
) )
@responses.activate
def test_v2_single_output_with_fake_amount_to_master(self):
"""
Tests a transaction with real amount of 5.0 XMR and faked amount of ~2^24 XMR
through a forged value of "ecdhInfo" field.
"""
responses.add(
responses.POST,
self.wallet_jsonrpc_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_master-wallet-00-get_accounts.json"
),
status=200,
)
responses.add(
responses.POST,
self.wallet_jsonrpc_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_master-wallet-01-query_key.json"
),
status=200,
)
responses.add(
responses.POST,
self.wallet_jsonrpc_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_master-wallet-02-addresses-account-0.json"
),
status=200,
)
responses.add(
responses.POST,
self.daemon_transactions_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_master-daemon-00-get_transactions.json"
),
status=200,
)
wallet = Wallet(JSONRPCWallet(host="127.0.0.1", port=38083))
daemon = Daemon(JSONRPCDaemon(host="127.0.0.1", port=38081))
tx = daemon.transactions(
"f7e60d07c8e201b779871e3817edf8388e6ea775922def5758aef231d3ced36a"
)[0]
outs = tx.outputs(wallet=wallet)
self.assertEqual(len(outs), 2)
for n, out in enumerate(outs):
self.assertIsNone(
out.payment,
f"Output {n} contains a payment with incorrect ecdhInfo",
)
@responses.activate
def test_v2_single_output_with_fake_amount_to_subaddr(self):
"""
Tests a transaction with real amount of 3.0 XMR and faked amount of ~2^24 XMR
through a forged value of "ecdhInfo" field.
"""
responses.add(
responses.POST,
self.wallet_jsonrpc_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_subaddr-wallet-00-get_accounts.json"
),
status=200,
)
responses.add(
responses.POST,
self.wallet_jsonrpc_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_subaddr-wallet-01-query_key.json"
),
status=200,
)
responses.add(
responses.POST,
self.wallet_jsonrpc_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_subaddr-wallet-02-addresses-account-0.json"
),
status=200,
)
responses.add(
responses.POST,
self.daemon_transactions_url,
json=self._read(
"test_v2_single_output_with_fake_amount_to_subaddr-daemon-00-get_transactions.json"
),
status=200,
)
wallet = Wallet(JSONRPCWallet(host="127.0.0.1", port=38083))
daemon = Daemon(JSONRPCDaemon(host="127.0.0.1", port=38081))
tx = daemon.transactions(
"54731f9263e92c9e249d8eb677f7c8f1c7edb9812092479f026062139842e0e0"
)[0]
outs = tx.outputs(wallet=wallet)
self.assertEqual(len(outs), 2)
for n, out in enumerate(outs):
self.assertIsNone(
out.payment,
f"Output {n} contains a payment with incorrect ecdhInfo",
)
def test_coinbase_no_own_output(self): def test_coinbase_no_own_output(self):
txdata = self._read("test_coinbase_no_own_output-26dcb5.json") txdata = self._read("test_coinbase_no_own_output-26dcb5.json")
tx = Transaction( tx = Transaction(

Loading…
Cancel
Save