From 10a52d8688285117f6702b328bff89f504d69512 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Mon, 26 Mar 2018 12:05:47 +0200 Subject: [PATCH] nem: multisig (basic functions, unit tests) --- src/apps/nem/multisig.py | 38 ++++++++++++++ src/apps/nem/transaction.py | 92 +++++++++++++-------------------- src/apps/nem/writers.py | 20 +++++++ tests/test_apps.nem.multisig.py | 86 ++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 56 deletions(-) create mode 100644 src/apps/nem/multisig.py create mode 100644 tests/test_apps.nem.multisig.py diff --git a/src/apps/nem/multisig.py b/src/apps/nem/multisig.py new file mode 100644 index 0000000000..6942d859c7 --- /dev/null +++ b/src/apps/nem/multisig.py @@ -0,0 +1,38 @@ + +from .helpers import * +from .writers import * +from trezor.crypto import hashlib + + +def nem_transaction_create_multisig(network: int, timestamp: int, signer_public_key: bytes, + fee: int, deadline: int, inner: bytes): + + w = nem_transaction_write_common(NEM_TRANSACTION_TYPE_MULTISIG, + nem_get_version(network), + timestamp, + signer_public_key, + fee, + deadline) + + write_bytes_with_length(w, bytearray(inner)) + + return w + + +def nem_transaction_create_multisig_signature(network: int, timestamp: int, signer_public_key: bytes, + fee: int, deadline: int, inner: bytes, address: str): + + w = nem_transaction_write_common(NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, + nem_get_version(network), + timestamp, + signer_public_key, + fee, + deadline) + + hash = hashlib.sha3_256(inner).digest(True) + + write_uint32(w, 4 + len(hash)) + write_bytes_with_length(w, hash) + write_bytes_with_length(w, address) + + return w diff --git a/src/apps/nem/transaction.py b/src/apps/nem/transaction.py index 8c7bffc161..f0f8b9485d 100644 --- a/src/apps/nem/transaction.py +++ b/src/apps/nem/transaction.py @@ -7,12 +7,12 @@ def nem_transaction_create_transfer(network: int, timestamp: int, signer_public_ recipient: str, amount: int, payload: bytearray = None, encrypted: bool = False, mosaics: int = 0) -> bytearray: - tx = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_TRANSFER, - _nem_get_version(network, mosaics), - timestamp, - signer_public_key, - fee, - deadline) + tx = nem_transaction_write_common(NEM_TRANSACTION_TYPE_TRANSFER, + nem_get_version(network, mosaics), + timestamp, + signer_public_key, + fee, + deadline) write_bytes_with_length(tx, bytearray(recipient)) write_uint64(tx, amount) @@ -38,12 +38,12 @@ def nem_transaction_create_provision_namespace(network: int, timestamp: int, sig deadline: int, namespace: str, parent: str, rental_sink: str, rental_fee: int) -> bytearray: - tx = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, - _nem_get_version(network), - timestamp, - signer_public_key, - fee, - deadline) + tx = nem_transaction_write_common(NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE, + nem_get_version(network), + timestamp, + signer_public_key, + fee, + deadline) write_bytes_with_length(tx, bytearray(rental_sink)) write_uint64(tx, rental_fee) @@ -62,12 +62,12 @@ def nem_transaction_create_mosaic_creation(network: int, timestamp: int, signer_ levy_type: int, levy_fee: int, levy_address: str, levy_namespace: str, levy_mosaic: str, creation_sink: str, creation_fee: int): - w = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_MOSAIC_CREATION, - _nem_get_version(network), - timestamp, - signer_public_key, - fee, - deadline) + w = nem_transaction_write_common(NEM_TRANSACTION_TYPE_MOSAIC_CREATION, + nem_get_version(network), + timestamp, + signer_public_key, + fee, + deadline) mosaics_w = bytearray() write_bytes_with_length(mosaics_w, bytearray(signer_public_key)) @@ -107,12 +107,12 @@ def nem_transaction_create_mosaic_creation(network: int, timestamp: int, signer_ def nem_transaction_create_mosaic_supply_change(network: int, timestamp: int, signer_public_key: bytes, fee: int, deadline: int, namespace: str, mosaic: str, type: int, delta: int): - w = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, - _nem_get_version(network), - timestamp, - signer_public_key, - fee, - deadline) + w = nem_transaction_write_common(NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE, + nem_get_version(network), + timestamp, + signer_public_key, + fee, + deadline) identifier_length = 4 + len(namespace) + 4 + len(mosaic) write_uint32(w, identifier_length) @@ -128,12 +128,12 @@ def nem_transaction_create_mosaic_supply_change(network: int, timestamp: int, si def nem_transaction_create_importance_transfer(network: int, timestamp: int, signer_public_key: bytes, fee: int, deadline: int, mode: int, remote: bytes): - w = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, - _nem_get_version(network), - timestamp, - signer_public_key, - fee, - deadline) + w = nem_transaction_write_common(NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER, + nem_get_version(network), + timestamp, + signer_public_key, + fee, + deadline) write_uint32(w, mode) write_bytes_with_length(w, bytearray(remote)) @@ -142,12 +142,12 @@ def nem_transaction_create_importance_transfer(network: int, timestamp: int, sig def nem_transaction_create_aggregate_modification(network: int, timestamp: int, signer_public_key: bytes, fee: int, deadline: int, modifications: int, relative_change: bool): - w = _nem_transaction_write_common(NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, - _nem_get_version(network, relative_change), - timestamp, - signer_public_key, - fee, - deadline) + w = nem_transaction_write_common(NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, + nem_get_version(network, relative_change), + timestamp, + signer_public_key, + fee, + deadline) write_uint32(w, modifications) return w @@ -188,23 +188,3 @@ def nem_transaction_write_mosaic(w: bytearray, namespace: str, mosaic: str, quan write_bytes_with_length(w, bytearray(namespace)) write_bytes_with_length(w, bytearray(mosaic)) write_uint64(w, quantity) - - -def _nem_transaction_write_common(tx_type: int, version: int, timestamp: int, signer: bytes, fee: int, deadline: int)\ - -> bytearray: - ret = bytearray() - write_uint32(ret, tx_type) - write_uint32(ret, version) - write_uint32(ret, timestamp) - - write_bytes_with_length(ret, bytearray(signer)) - write_uint64(ret, fee) - write_uint32(ret, deadline) - - return ret - - -def _nem_get_version(network, mosaics=None) -> int: - if mosaics: - return network << 24 | 2 - return network << 24 | 1 diff --git a/src/apps/nem/writers.py b/src/apps/nem/writers.py index 4708fa6a97..0f3544328c 100644 --- a/src/apps/nem/writers.py +++ b/src/apps/nem/writers.py @@ -24,3 +24,23 @@ def write_bytes(w, buf: bytearray): def write_bytes_with_length(w, buf: bytearray): write_uint32(w, len(buf)) write_bytes(w, buf) + + +def nem_transaction_write_common(tx_type: int, version: int, timestamp: int, signer: bytes, fee: int, deadline: int)\ + -> bytearray: + ret = bytearray() + write_uint32(ret, tx_type) + write_uint32(ret, version) + write_uint32(ret, timestamp) + + write_bytes_with_length(ret, bytearray(signer)) + write_uint64(ret, fee) + write_uint32(ret, deadline) + + return ret + + +def nem_get_version(network, mosaics=None) -> int: + if mosaics: + return network << 24 | 2 + return network << 24 | 1 diff --git a/tests/test_apps.nem.multisig.py b/tests/test_apps.nem.multisig.py new file mode 100644 index 0000000000..061838f235 --- /dev/null +++ b/tests/test_apps.nem.multisig.py @@ -0,0 +1,86 @@ +from common import * + +from apps.nem.transaction import * +from apps.nem.multisig import * + + +class TestNemMultisig(unittest.TestCase): + + def test_nem_multisig(self): + # http://bob.nem.ninja:8765/#/multisig/7d3a7087023ee29005262016706818579a2b5499eb9ca76bad98c1e6f4c46642 + + base_tx = nem_transaction_create_aggregate_modification(NEM_NETWORK_TESTNET, + 3939039, + unhexlify("abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"), + 16000000, + 3960639, + 1, + False) + + base_tx = nem_transaction_write_cosignatory_modification(base_tx, 2, unhexlify("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3")) + multisig = nem_transaction_create_multisig(NEM_NETWORK_TESTNET, + 3939039, + unhexlify("59d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e"), + 6000000, + 3960639, + base_tx) + + self.assertEqual(multisig, unhexlify("0410000001000098df1a3c002000000059d89076964742ef2a2089d26a5aa1d2c7a7bb052a46c1de159891e91ad3d76e808d5b00000000003f6f3c006c0000000110000001000098df1a3c0020000000abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac0024f400000000003f6f3c0001000000280000000200000020000000e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3")) + + address = "TCRXYUQIMFA7AOGL5LF3YWLC7VABLYUMJ5ACBUNL" + multisig = nem_transaction_create_multisig_signature(NEM_NETWORK_TESTNET, + 3939891, + unhexlify("71cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4"), + 6000000, + 3961491, + base_tx, + address) + + self.assertEqual(multisig, unhexlify("0210000001000098331e3c002000000071cba4f2a28fd19f902ba40e9937994154d9eeaad0631d25d525ec37922567d4808d5b000000000093723c0024000000200000008ec165580bdabfd31ce6007a1748ce5bdf30eab7a214743097de3bc822ac7e002800000054435258595551494d464137414f474c354c463359574c43375641424c59554d4a35414342554e4c")) + + def test_nem_multisig_2(self): + # http://chain.nem.ninja/#/multisig/1016cf3bdd61bd57b9b2b07b6ff2dee390279d8d899265bdc23d42360abe2e6c + + base_tx = nem_transaction_create_provision_namespace(NEM_NETWORK_MAINNET, + 59414272, + unhexlify("a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a"), + 20000000, + 59500672, + "dim", + "", + "NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA", + 5000000000) + + multisig = nem_transaction_create_multisig(NEM_NETWORK_MAINNET, + 59414272, + unhexlify("cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9"), + 6000000, + 59500672, + base_tx) + + self.assertEqual(multisig, unhexlify("041000000100006800978a0320000000cfe58463f0eaebceb5d00717f8aead49171a5d7c08f6b1299bd534f11715acc9808d5b000000000080e88b037b000000012000000100006800978a0320000000a1df5306355766bd2f9a64efdc089eb294be265987b3359093ae474c051d7d5a002d31010000000080e88b03280000004e414d4553504143455748344d4b464d42435646455244504f4f5034464b374d54425844505a5a4100f2052a010000000300000064696dffffffff")) + + address = "NDDRG3UEB5LZZZMDWBE4RTKZK73JBHPAIWBHCFMV" + multisig = nem_transaction_create_multisig_signature(NEM_NETWORK_MAINNET, + 59414342, + unhexlify("1b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2"), + 6000000, + 59500742, + base_tx, + address) + + self.assertEqual(multisig, unhexlify("021000000100006846978a03200000001b49b80203007117d034e45234ffcdf402c044aeef6dbb06351f346ca892bce2808d5b0000000000c6e88b032400000020000000bfa2088f7720f89dd4664d650e321dabd02fab61b7355bc88a391a848a49786a280000004e4444524733554542354c5a5a5a4d445742453452544b5a4b37334a424850414957424843464d56")) + + multisig = nem_transaction_create_multisig_signature(NEM_NETWORK_MAINNET, + 59414381, + unhexlify("7ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87"), + 6000000, + 59500781, + base_tx, + address) + + self.assertEqual(multisig, unhexlify("02100000010000686d978a03200000007ba4b39209f1b9846b098fe43f74381e43cb2882ccde780f558a63355840aa87808d5b0000000000ede88b032400000020000000bfa2088f7720f89dd4664d650e321dabd02fab61b7355bc88a391a848a49786a280000004e4444524733554542354c5a5a5a4d445742453452544b5a4b37334a424850414957424843464d56")) + + +if __name__ == '__main__': + unittest.main()