mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-26 16:18:22 +00:00
apps: unify common writer logic
This commit is contained in:
parent
2f910839fe
commit
f7c1465d57
68
src/apps/common/writers.py
Normal file
68
src/apps/common/writers.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
def empty_bytearray(preallocate: int) -> bytearray:
|
||||||
|
"""
|
||||||
|
Returns bytearray that won't allocate for at least `preallocate` bytes.
|
||||||
|
Useful in case you want to avoid allocating too often.
|
||||||
|
"""
|
||||||
|
b = bytearray(preallocate)
|
||||||
|
b[:] = bytes()
|
||||||
|
return b
|
||||||
|
|
||||||
|
|
||||||
|
def write_uint8(w: bytearray, n: int) -> int:
|
||||||
|
assert 0 <= n <= 0xFF
|
||||||
|
w.append(n)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def write_uint32_le(w: bytearray, n: int) -> int:
|
||||||
|
assert 0 <= n <= 0xFFFFFFFF
|
||||||
|
w.append(n & 0xFF)
|
||||||
|
w.append((n >> 8) & 0xFF)
|
||||||
|
w.append((n >> 16) & 0xFF)
|
||||||
|
w.append((n >> 24) & 0xFF)
|
||||||
|
return 4
|
||||||
|
|
||||||
|
|
||||||
|
def write_uint32_be(w: bytearray, n: int) -> int:
|
||||||
|
assert 0 <= n <= 0xFFFFFFFF
|
||||||
|
w.append((n >> 24) & 0xFF)
|
||||||
|
w.append((n >> 16) & 0xFF)
|
||||||
|
w.append((n >> 8) & 0xFF)
|
||||||
|
w.append(n & 0xFF)
|
||||||
|
return 4
|
||||||
|
|
||||||
|
|
||||||
|
def write_uint64_le(w: bytearray, n: int) -> int:
|
||||||
|
assert 0 <= n <= 0xFFFFFFFFFFFFFFFF
|
||||||
|
w.append(n & 0xFF)
|
||||||
|
w.append((n >> 8) & 0xFF)
|
||||||
|
w.append((n >> 16) & 0xFF)
|
||||||
|
w.append((n >> 24) & 0xFF)
|
||||||
|
w.append((n >> 32) & 0xFF)
|
||||||
|
w.append((n >> 40) & 0xFF)
|
||||||
|
w.append((n >> 48) & 0xFF)
|
||||||
|
w.append((n >> 56) & 0xFF)
|
||||||
|
return 8
|
||||||
|
|
||||||
|
|
||||||
|
def write_uint64_be(w: bytearray, n: int) -> int:
|
||||||
|
assert 0 <= n <= 0xFFFFFFFFFFFFFFFF
|
||||||
|
w.append((n >> 56) & 0xFF)
|
||||||
|
w.append((n >> 48) & 0xFF)
|
||||||
|
w.append((n >> 40) & 0xFF)
|
||||||
|
w.append((n >> 32) & 0xFF)
|
||||||
|
w.append((n >> 24) & 0xFF)
|
||||||
|
w.append((n >> 16) & 0xFF)
|
||||||
|
w.append((n >> 8) & 0xFF)
|
||||||
|
w.append(n & 0xFF)
|
||||||
|
return 8
|
||||||
|
|
||||||
|
|
||||||
|
def write_bytes(w: bytearray, b: bytes) -> int:
|
||||||
|
w.extend(b)
|
||||||
|
return len(b)
|
||||||
|
|
||||||
|
|
||||||
|
def write_bytes_reversed(w: bytearray, b: bytes) -> int:
|
||||||
|
w.extend(bytes(reversed(b)))
|
||||||
|
return len(b)
|
@ -6,26 +6,29 @@ from ..helpers import (
|
|||||||
NEM_TRANSACTION_TYPE_MOSAIC_CREATION,
|
NEM_TRANSACTION_TYPE_MOSAIC_CREATION,
|
||||||
NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE,
|
NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE,
|
||||||
)
|
)
|
||||||
from ..writers import write_bytes_with_length, write_common, write_uint32, write_uint64
|
from ..writers import (
|
||||||
|
serialize_tx_common,
|
||||||
|
write_bytes_with_len,
|
||||||
|
write_uint32_le,
|
||||||
|
write_uint64_le,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def serialize_mosaic_creation(
|
def serialize_mosaic_creation(
|
||||||
common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes
|
common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes
|
||||||
):
|
):
|
||||||
w = write_common(
|
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_CREATION)
|
||||||
common, bytearray(public_key), NEM_TRANSACTION_TYPE_MOSAIC_CREATION
|
|
||||||
)
|
|
||||||
|
|
||||||
mosaics_w = bytearray()
|
mosaics_w = bytearray()
|
||||||
write_bytes_with_length(mosaics_w, bytearray(public_key))
|
write_bytes_with_len(mosaics_w, public_key)
|
||||||
identifier_length = (
|
|
||||||
4 + len(creation.definition.namespace) + 4 + len(creation.definition.mosaic)
|
identifier_w = bytearray()
|
||||||
)
|
write_bytes_with_len(identifier_w, creation.definition.namespace.encode())
|
||||||
write_uint32(mosaics_w, identifier_length)
|
write_bytes_with_len(identifier_w, creation.definition.mosaic.encode())
|
||||||
write_bytes_with_length(mosaics_w, bytearray(creation.definition.namespace))
|
|
||||||
write_bytes_with_length(mosaics_w, bytearray(creation.definition.mosaic))
|
write_bytes_with_len(mosaics_w, identifier_w)
|
||||||
write_bytes_with_length(mosaics_w, bytearray(creation.definition.description))
|
write_bytes_with_len(mosaics_w, creation.definition.description.encode())
|
||||||
write_uint32(mosaics_w, 4) # number of properties
|
write_uint32_le(mosaics_w, 4) # number of properties
|
||||||
|
|
||||||
_write_property(mosaics_w, "divisibility", creation.definition.divisibility)
|
_write_property(mosaics_w, "divisibility", creation.definition.divisibility)
|
||||||
_write_property(mosaics_w, "initialSupply", creation.definition.supply)
|
_write_property(mosaics_w, "initialSupply", creation.definition.supply)
|
||||||
@ -33,37 +36,29 @@ def serialize_mosaic_creation(
|
|||||||
_write_property(mosaics_w, "transferable", creation.definition.transferable)
|
_write_property(mosaics_w, "transferable", creation.definition.transferable)
|
||||||
|
|
||||||
if creation.definition.levy:
|
if creation.definition.levy:
|
||||||
levy_identifier_length = (
|
|
||||||
4
|
levy_identifier_w = bytearray()
|
||||||
+ len(creation.definition.levy_namespace)
|
write_bytes_with_len(
|
||||||
+ 4
|
levy_identifier_w, creation.definition.levy_namespace.encode()
|
||||||
+ len(creation.definition.levy_mosaic)
|
|
||||||
)
|
)
|
||||||
write_uint32(
|
write_bytes_with_len(
|
||||||
mosaics_w,
|
levy_identifier_w, creation.definition.levy_mosaic.encode()
|
||||||
4
|
|
||||||
+ 4
|
|
||||||
+ len(creation.definition.levy_address)
|
|
||||||
+ 4
|
|
||||||
+ levy_identifier_length
|
|
||||||
+ 8,
|
|
||||||
)
|
)
|
||||||
write_uint32(mosaics_w, creation.definition.levy)
|
|
||||||
write_bytes_with_length(mosaics_w, bytearray(creation.definition.levy_address))
|
levy_w = bytearray()
|
||||||
write_uint32(mosaics_w, levy_identifier_length)
|
write_uint32_le(levy_w, creation.definition.levy)
|
||||||
write_bytes_with_length(
|
write_bytes_with_len(levy_w, creation.definition.levy_address.encode())
|
||||||
mosaics_w, bytearray(creation.definition.levy_namespace)
|
write_bytes_with_len(levy_w, levy_identifier_w)
|
||||||
)
|
write_uint64_le(levy_w, creation.definition.fee)
|
||||||
write_bytes_with_length(mosaics_w, bytearray(creation.definition.levy_mosaic))
|
|
||||||
write_uint64(mosaics_w, creation.definition.fee)
|
write_bytes_with_len(mosaics_w, levy_w)
|
||||||
else:
|
else:
|
||||||
write_uint32(mosaics_w, 0)
|
write_uint32_le(mosaics_w, 0) # no levy
|
||||||
|
|
||||||
# write mosaic bytes with length
|
write_bytes_with_len(w, mosaics_w)
|
||||||
write_bytes_with_length(w, mosaics_w)
|
|
||||||
|
|
||||||
write_bytes_with_length(w, bytearray(creation.sink))
|
write_bytes_with_len(w, creation.sink.encode())
|
||||||
write_uint64(w, creation.fee)
|
write_uint64_le(w, creation.fee)
|
||||||
|
|
||||||
return w
|
return w
|
||||||
|
|
||||||
@ -71,17 +66,18 @@ def serialize_mosaic_creation(
|
|||||||
def serialize_mosaic_supply_change(
|
def serialize_mosaic_supply_change(
|
||||||
common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes
|
common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes
|
||||||
):
|
):
|
||||||
w = write_common(
|
w = serialize_tx_common(
|
||||||
common, bytearray(public_key), NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE
|
common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE
|
||||||
)
|
)
|
||||||
|
|
||||||
identifier_length = 4 + len(change.namespace) + 4 + len(change.mosaic)
|
identifier_w = bytearray()
|
||||||
write_uint32(w, identifier_length)
|
write_bytes_with_len(identifier_w, change.namespace.encode())
|
||||||
write_bytes_with_length(w, bytearray(change.namespace))
|
write_bytes_with_len(identifier_w, change.mosaic.encode())
|
||||||
write_bytes_with_length(w, bytearray(change.mosaic))
|
|
||||||
|
|
||||||
write_uint32(w, change.type)
|
write_bytes_with_len(w, identifier_w)
|
||||||
write_uint64(w, change.delta)
|
|
||||||
|
write_uint32_le(w, change.type)
|
||||||
|
write_uint64_le(w, change.delta)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
@ -98,8 +94,10 @@ def _write_property(w: bytearray, name: str, value):
|
|||||||
value = "false"
|
value = "false"
|
||||||
elif type(value) == int:
|
elif type(value) == int:
|
||||||
value = str(value)
|
value = str(value)
|
||||||
elif type(value) != str:
|
if type(value) != str:
|
||||||
raise ValueError("Incompatible value type")
|
raise ValueError("Incompatible value type")
|
||||||
write_uint32(w, 4 + len(name) + 4 + len(value))
|
name = name.encode()
|
||||||
write_bytes_with_length(w, bytearray(name))
|
value = value.encode()
|
||||||
write_bytes_with_length(w, bytearray(value))
|
write_uint32_le(w, 4 + len(name) + 4 + len(value))
|
||||||
|
write_bytes_with_len(w, name)
|
||||||
|
write_bytes_with_len(w, value)
|
||||||
|
@ -30,8 +30,8 @@ async def aggregate_modification(
|
|||||||
w = serialize.serialize_aggregate_modification(common, aggr, public_key)
|
w = serialize.serialize_aggregate_modification(common, aggr, public_key)
|
||||||
|
|
||||||
for m in aggr.modifications:
|
for m in aggr.modifications:
|
||||||
serialize.serialize_cosignatory_modification(w, m.type, m.public_key)
|
serialize.write_cosignatory_modification(w, m.type, m.public_key)
|
||||||
|
|
||||||
if aggr.relative_change:
|
if aggr.relative_change:
|
||||||
serialize.serialize_minimum_cosignatories(w, aggr.relative_change)
|
serialize.write_minimum_cosignatories(w, aggr.relative_change)
|
||||||
return w
|
return w
|
||||||
|
@ -7,12 +7,12 @@ from ..helpers import (
|
|||||||
NEM_TRANSACTION_TYPE_MULTISIG,
|
NEM_TRANSACTION_TYPE_MULTISIG,
|
||||||
NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE,
|
NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE,
|
||||||
)
|
)
|
||||||
from ..writers import write_bytes_with_length, write_common, write_uint32
|
from ..writers import serialize_tx_common, write_bytes_with_len, write_uint32_le
|
||||||
|
|
||||||
|
|
||||||
def serialize_multisig(common: NEMTransactionCommon, public_key: bytes, inner: bytes):
|
def serialize_multisig(common: NEMTransactionCommon, public_key: bytes, inner: bytes):
|
||||||
w = write_common(common, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG)
|
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG)
|
||||||
write_bytes_with_length(w, bytearray(inner))
|
write_bytes_with_len(w, inner)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
@ -22,15 +22,13 @@ def serialize_multisig_signature(
|
|||||||
inner: bytes,
|
inner: bytes,
|
||||||
address_public_key: bytes,
|
address_public_key: bytes,
|
||||||
):
|
):
|
||||||
address = nem.compute_address(address_public_key, common.network)
|
w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE)
|
||||||
w = write_common(
|
|
||||||
common, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE
|
|
||||||
)
|
|
||||||
digest = hashlib.sha3_256(inner, keccak=True).digest()
|
digest = hashlib.sha3_256(inner, keccak=True).digest()
|
||||||
|
address = nem.compute_address(address_public_key, common.network)
|
||||||
|
|
||||||
write_uint32(w, 4 + len(digest))
|
write_uint32_le(w, 4 + len(digest))
|
||||||
write_bytes_with_length(w, digest)
|
write_bytes_with_len(w, digest)
|
||||||
write_bytes_with_length(w, address)
|
write_bytes_with_len(w, address)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
@ -41,25 +39,22 @@ def serialize_aggregate_modification(
|
|||||||
if mod.relative_change:
|
if mod.relative_change:
|
||||||
version = common.network << 24 | 2
|
version = common.network << 24 | 2
|
||||||
|
|
||||||
w = write_common(
|
w = serialize_tx_common(
|
||||||
common,
|
common, public_key, NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, version
|
||||||
bytearray(public_key),
|
|
||||||
NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION,
|
|
||||||
version,
|
|
||||||
)
|
)
|
||||||
write_uint32(w, len(mod.modifications))
|
write_uint32_le(w, len(mod.modifications))
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
def serialize_cosignatory_modification(
|
def write_cosignatory_modification(
|
||||||
w: bytearray, type: int, cosignatory_pubkey: bytes
|
w: bytearray, cosignatory_type: int, cosignatory_pubkey: bytes
|
||||||
):
|
):
|
||||||
write_uint32(w, 4 + 4 + len(cosignatory_pubkey))
|
write_uint32_le(w, 4 + 4 + len(cosignatory_pubkey))
|
||||||
write_uint32(w, type)
|
write_uint32_le(w, cosignatory_type)
|
||||||
write_bytes_with_length(w, bytearray(cosignatory_pubkey))
|
write_bytes_with_len(w, cosignatory_pubkey)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
def serialize_minimum_cosignatories(w: bytearray, relative_change: int):
|
def write_minimum_cosignatories(w: bytearray, relative_change: int):
|
||||||
write_uint32(w, 4)
|
write_uint32_le(w, 4)
|
||||||
write_uint32(w, relative_change)
|
write_uint32_le(w, relative_change)
|
||||||
|
@ -2,22 +2,27 @@ from trezor.messages.NEMProvisionNamespace import NEMProvisionNamespace
|
|||||||
from trezor.messages.NEMTransactionCommon import NEMTransactionCommon
|
from trezor.messages.NEMTransactionCommon import NEMTransactionCommon
|
||||||
|
|
||||||
from ..helpers import NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
from ..helpers import NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
||||||
from ..writers import write_bytes_with_length, write_common, write_uint32, write_uint64
|
from ..writers import (
|
||||||
|
serialize_tx_common,
|
||||||
|
write_bytes_with_len,
|
||||||
|
write_uint32_le,
|
||||||
|
write_uint64_le,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def serialize_provision_namespace(
|
def serialize_provision_namespace(
|
||||||
common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes
|
common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
tx = write_common(
|
tx = serialize_tx_common(
|
||||||
common, bytearray(public_key), NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
common, public_key, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE
|
||||||
)
|
)
|
||||||
|
|
||||||
write_bytes_with_length(tx, bytearray(namespace.sink))
|
write_bytes_with_len(tx, namespace.sink.encode())
|
||||||
write_uint64(tx, namespace.fee)
|
write_uint64_le(tx, namespace.fee)
|
||||||
write_bytes_with_length(tx, bytearray(namespace.namespace))
|
write_bytes_with_len(tx, namespace.namespace.encode())
|
||||||
if namespace.parent:
|
if namespace.parent:
|
||||||
write_bytes_with_length(tx, bytearray(namespace.parent))
|
write_bytes_with_len(tx, namespace.parent.encode())
|
||||||
else:
|
else:
|
||||||
write_uint32(tx, 0xffffffff)
|
write_uint32_le(tx, 0xffffffff)
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
|
@ -15,8 +15,8 @@ async def sign_tx(ctx, msg: NEMSignTx):
|
|||||||
|
|
||||||
if msg.multisig:
|
if msg.multisig:
|
||||||
public_key = msg.multisig.signer
|
public_key = msg.multisig.signer
|
||||||
await multisig.ask(ctx, msg)
|
|
||||||
common = msg.multisig
|
common = msg.multisig
|
||||||
|
await multisig.ask(ctx, msg)
|
||||||
else:
|
else:
|
||||||
public_key = seed.remove_ed25519_prefix(node.public_key())
|
public_key = seed.remove_ed25519_prefix(node.public_key())
|
||||||
common = msg.transaction
|
common = msg.transaction
|
||||||
|
@ -10,7 +10,12 @@ from ..helpers import (
|
|||||||
NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER,
|
NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER,
|
||||||
NEM_TRANSACTION_TYPE_TRANSFER,
|
NEM_TRANSACTION_TYPE_TRANSFER,
|
||||||
)
|
)
|
||||||
from ..writers import write_bytes_with_length, write_common, write_uint32, write_uint64
|
from ..writers import (
|
||||||
|
serialize_tx_common,
|
||||||
|
write_bytes_with_len,
|
||||||
|
write_uint32_le,
|
||||||
|
write_uint64_le,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def serialize_transfer(
|
def serialize_transfer(
|
||||||
@ -20,52 +25,54 @@ def serialize_transfer(
|
|||||||
payload: bytes = None,
|
payload: bytes = None,
|
||||||
encrypted: bool = False,
|
encrypted: bool = False,
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
tx = write_common(
|
tx = serialize_tx_common(
|
||||||
common,
|
common,
|
||||||
bytearray(public_key),
|
public_key,
|
||||||
NEM_TRANSACTION_TYPE_TRANSFER,
|
NEM_TRANSACTION_TYPE_TRANSFER,
|
||||||
_get_version(common.network, transfer.mosaics),
|
_get_version(common.network, transfer.mosaics),
|
||||||
)
|
)
|
||||||
|
|
||||||
write_bytes_with_length(tx, bytearray(transfer.recipient))
|
write_bytes_with_len(tx, transfer.recipient.encode())
|
||||||
write_uint64(tx, transfer.amount)
|
write_uint64_le(tx, transfer.amount)
|
||||||
|
|
||||||
if payload:
|
if payload:
|
||||||
# payload + payload size (u32) + encryption flag (u32)
|
# payload + payload size (u32) + encryption flag (u32)
|
||||||
write_uint32(tx, len(payload) + 2 * 4)
|
write_uint32_le(tx, len(payload) + 2 * 4)
|
||||||
if encrypted:
|
if encrypted:
|
||||||
write_uint32(tx, 0x02)
|
write_uint32_le(tx, 0x02)
|
||||||
else:
|
else:
|
||||||
write_uint32(tx, 0x01)
|
write_uint32_le(tx, 0x01)
|
||||||
write_bytes_with_length(tx, bytearray(payload))
|
write_bytes_with_len(tx, payload)
|
||||||
else:
|
else:
|
||||||
write_uint32(tx, 0)
|
write_uint32_le(tx, 0)
|
||||||
|
|
||||||
if transfer.mosaics:
|
if transfer.mosaics:
|
||||||
write_uint32(tx, len(transfer.mosaics))
|
write_uint32_le(tx, len(transfer.mosaics))
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
|
||||||
def serialize_mosaic(w: bytearray, namespace: str, mosaic: str, quantity: int):
|
def serialize_mosaic(w: bytearray, namespace: str, mosaic: str, quantity: int):
|
||||||
identifier_length = 4 + len(namespace) + 4 + len(mosaic)
|
identifier_w = bytearray()
|
||||||
# indentifier length (u32) + quantity (u64) + identifier size
|
write_bytes_with_len(identifier_w, namespace.encode())
|
||||||
write_uint32(w, 4 + 8 + identifier_length)
|
write_bytes_with_len(identifier_w, mosaic.encode())
|
||||||
write_uint32(w, identifier_length)
|
|
||||||
write_bytes_with_length(w, bytearray(namespace))
|
mosaic_w = bytearray()
|
||||||
write_bytes_with_length(w, bytearray(mosaic))
|
write_bytes_with_len(mosaic_w, identifier_w)
|
||||||
write_uint64(w, quantity)
|
write_uint64_le(mosaic_w, quantity)
|
||||||
|
|
||||||
|
write_bytes_with_len(w, mosaic_w)
|
||||||
|
|
||||||
|
|
||||||
def serialize_importance_transfer(
|
def serialize_importance_transfer(
|
||||||
common: NEMTransactionCommon, imp: NEMImportanceTransfer, public_key: bytes
|
common: NEMTransactionCommon, imp: NEMImportanceTransfer, public_key: bytes
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
w = write_common(
|
w = serialize_tx_common(
|
||||||
common, bytearray(public_key), NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER
|
common, public_key, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER
|
||||||
)
|
)
|
||||||
|
|
||||||
write_uint32(w, imp.mode)
|
write_uint32_le(w, imp.mode)
|
||||||
write_bytes_with_length(w, bytearray(imp.public_key))
|
write_bytes_with_len(w, imp.public_key)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
@ -109,8 +116,8 @@ def are_mosaics_equal(a: NEMMosaic, b: NEMMosaic) -> bool:
|
|||||||
|
|
||||||
def merge_mosaics(mosaics: list) -> list:
|
def merge_mosaics(mosaics: list) -> list:
|
||||||
if not mosaics:
|
if not mosaics:
|
||||||
return list()
|
return []
|
||||||
ret = list()
|
ret = []
|
||||||
for i in mosaics:
|
for i in mosaics:
|
||||||
found = False
|
found = False
|
||||||
for k, y in enumerate(ret):
|
for k, y in enumerate(ret):
|
||||||
|
@ -1,49 +1,29 @@
|
|||||||
from trezor.messages.NEMTransactionCommon import NEMTransactionCommon
|
from trezor.messages.NEMTransactionCommon import NEMTransactionCommon
|
||||||
|
|
||||||
|
from apps.common.writers import write_bytes, write_uint32_le, write_uint64_le
|
||||||
def write_uint32(w, n: int):
|
|
||||||
w.append(n & 0xFF)
|
|
||||||
w.append((n >> 8) & 0xFF)
|
|
||||||
w.append((n >> 16) & 0xFF)
|
|
||||||
w.append((n >> 24) & 0xFF)
|
|
||||||
|
|
||||||
|
|
||||||
def write_uint64(w, n: int):
|
def serialize_tx_common(
|
||||||
w.append(n & 0xFF)
|
|
||||||
w.append((n >> 8) & 0xFF)
|
|
||||||
w.append((n >> 16) & 0xFF)
|
|
||||||
w.append((n >> 24) & 0xFF)
|
|
||||||
w.append((n >> 32) & 0xFF)
|
|
||||||
w.append((n >> 40) & 0xFF)
|
|
||||||
w.append((n >> 48) & 0xFF)
|
|
||||||
w.append((n >> 56) & 0xFF)
|
|
||||||
|
|
||||||
|
|
||||||
def write_bytes(w, buf: bytearray):
|
|
||||||
w.extend(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def write_bytes_with_length(w, buf: bytearray):
|
|
||||||
write_uint32(w, len(buf))
|
|
||||||
write_bytes(w, buf)
|
|
||||||
|
|
||||||
|
|
||||||
def write_common(
|
|
||||||
common: NEMTransactionCommon,
|
common: NEMTransactionCommon,
|
||||||
public_key: bytearray,
|
public_key: bytearray,
|
||||||
transaction_type: int,
|
transaction_type: int,
|
||||||
version: int = None,
|
version: int = None,
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
ret = bytearray()
|
w = bytearray()
|
||||||
|
|
||||||
write_uint32(ret, transaction_type)
|
write_uint32_le(w, transaction_type)
|
||||||
if version is None:
|
if version is None:
|
||||||
version = common.network << 24 | 1
|
version = common.network << 24 | 1
|
||||||
write_uint32(ret, version)
|
write_uint32_le(w, version)
|
||||||
write_uint32(ret, common.timestamp)
|
write_uint32_le(w, common.timestamp)
|
||||||
|
|
||||||
write_bytes_with_length(ret, public_key)
|
write_bytes_with_len(w, public_key)
|
||||||
write_uint64(ret, common.fee)
|
write_uint64_le(w, common.fee)
|
||||||
write_uint32(ret, common.deadline)
|
write_uint32_le(w, common.deadline)
|
||||||
|
|
||||||
return ret
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def write_bytes_with_len(w, buf: bytes):
|
||||||
|
write_uint32_le(w, len(buf))
|
||||||
|
write_bytes(w, buf)
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
# the other four the record type (amount, fee, destination..) and then
|
# the other four the record type (amount, fee, destination..) and then
|
||||||
# the actual data follow. This currently only supports the Payment
|
# the actual data follow. This currently only supports the Payment
|
||||||
# transaction type and the fields that are required for it.
|
# transaction type and the fields that are required for it.
|
||||||
#
|
|
||||||
|
from micropython import const
|
||||||
|
|
||||||
from trezor.messages.RippleSignTx import RippleSignTx
|
from trezor.messages.RippleSignTx import RippleSignTx
|
||||||
|
|
||||||
from . import helpers
|
from . import helpers
|
||||||
@ -78,44 +80,50 @@ def write_type(w: bytearray, field: dict):
|
|||||||
|
|
||||||
|
|
||||||
def serialize_amount(value: int) -> bytearray:
|
def serialize_amount(value: int) -> bytearray:
|
||||||
if value < 0 or isinstance(value, float):
|
MAX_ALLOWED_AMOUNT = const(100000000000)
|
||||||
raise ValueError("Only positive integers are supported")
|
|
||||||
if value > 100000000000: # max allowed value
|
if value < 0:
|
||||||
raise ValueError("Value is larger than 100000000000")
|
raise ValueError("Only non-negative integers are supported")
|
||||||
|
if value > MAX_ALLOWED_AMOUNT:
|
||||||
|
raise ValueError("Value is too large")
|
||||||
|
|
||||||
b = bytearray(value.to_bytes(8, "big"))
|
b = bytearray(value.to_bytes(8, "big"))
|
||||||
# Clear first bit to indicate XRP
|
b[0] &= 0x7f # clear first bit to indicate XRP
|
||||||
b[0] &= 0x7f
|
b[0] |= 0x40 # set second bit to indicate positive number
|
||||||
# Set second bit to indicate positive number
|
|
||||||
b[0] |= 0x40
|
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
|
||||||
def write_bytes(w: bytearray, value: bytes):
|
def write_bytes(w: bytearray, value: bytes):
|
||||||
"""Serialize a variable length bytes."""
|
"""Serialize a variable length bytes."""
|
||||||
serialize_varint(w, len(value))
|
write_varint(w, len(value))
|
||||||
w.extend(value)
|
w.extend(value)
|
||||||
|
|
||||||
|
|
||||||
def serialize_varint(w, val):
|
def write_varint(w: bytearray, val: int):
|
||||||
"""https://ripple.com/wiki/Binary_Format#Variable_Length_Data_Encoding"""
|
"""
|
||||||
|
Implements variable-length int encoding from Ripple.
|
||||||
def rshift(val, n):
|
See: https://ripple.com/wiki/Binary_Format#Variable_Length_Data_Encoding
|
||||||
# http://stackoverflow.com/a/5833119/15677
|
"""
|
||||||
return (val % 0x100000000) >> n
|
if val < 0:
|
||||||
|
raise ValueError("Only non-negative integers are supported")
|
||||||
assert val >= 0
|
elif val < 192:
|
||||||
|
w.append(val)
|
||||||
b = bytearray()
|
|
||||||
if val < 192:
|
|
||||||
b.append(val)
|
|
||||||
elif val <= 12480:
|
elif val <= 12480:
|
||||||
val -= 193
|
val -= 193
|
||||||
b.extend([193 + rshift(val, 8), val & 0xff])
|
w.append(193 + rshift(val, 8))
|
||||||
|
w.append(val & 0xff)
|
||||||
elif val <= 918744:
|
elif val <= 918744:
|
||||||
val -= 12481
|
val -= 12481
|
||||||
b.extend([241 + rshift(val, 16), rshift(val, 8) & 0xff, val & 0xff])
|
w.append(241 + rshift(val, 16))
|
||||||
|
w.append(rshift(val, 8) & 0xff)
|
||||||
|
w.append(val & 0xff)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Variable integer overflow.")
|
raise ValueError("Value is too large")
|
||||||
|
|
||||||
w.extend(b)
|
|
||||||
|
def rshift(val, n):
|
||||||
|
"""
|
||||||
|
Implements signed right-shift.
|
||||||
|
See: http://stackoverflow.com/a/5833119/15677
|
||||||
|
"""
|
||||||
|
return (val % 0x100000000) >> n
|
||||||
|
@ -2,43 +2,43 @@ from apps.stellar import consts, writers
|
|||||||
from apps.stellar.operations import layout, serialize
|
from apps.stellar.operations import layout, serialize
|
||||||
|
|
||||||
|
|
||||||
async def operation(ctx, w, op):
|
async def process_operation(ctx, w, op):
|
||||||
if op.source_account:
|
if op.source_account:
|
||||||
await layout.confirm_source_account(ctx, op.source_account)
|
await layout.confirm_source_account(ctx, op.source_account)
|
||||||
serialize.serialize_account(w, op.source_account)
|
serialize.write_account(w, op.source_account)
|
||||||
writers.write_uint32(w, consts.get_op_code(op))
|
writers.write_uint32(w, consts.get_op_code(op))
|
||||||
if isinstance(op, serialize.StellarAccountMergeOp):
|
if isinstance(op, serialize.StellarAccountMergeOp):
|
||||||
await layout.confirm_account_merge_op(ctx, op)
|
await layout.confirm_account_merge_op(ctx, op)
|
||||||
serialize.serialize_account_merge_op(w, op)
|
serialize.write_account_merge_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarAllowTrustOp):
|
elif isinstance(op, serialize.StellarAllowTrustOp):
|
||||||
await layout.confirm_allow_trust_op(ctx, op)
|
await layout.confirm_allow_trust_op(ctx, op)
|
||||||
serialize.serialize_allow_trust_op(w, op)
|
serialize.write_allow_trust_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarBumpSequenceOp):
|
elif isinstance(op, serialize.StellarBumpSequenceOp):
|
||||||
await layout.confirm_bump_sequence_op(ctx, op)
|
await layout.confirm_bump_sequence_op(ctx, op)
|
||||||
serialize.serialize_bump_sequence_op(w, op)
|
serialize.write_bump_sequence_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarChangeTrustOp):
|
elif isinstance(op, serialize.StellarChangeTrustOp):
|
||||||
await layout.confirm_change_trust_op(ctx, op)
|
await layout.confirm_change_trust_op(ctx, op)
|
||||||
serialize.serialize_change_trust_op(w, op)
|
serialize.write_change_trust_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarCreateAccountOp):
|
elif isinstance(op, serialize.StellarCreateAccountOp):
|
||||||
await layout.confirm_create_account_op(ctx, op)
|
await layout.confirm_create_account_op(ctx, op)
|
||||||
serialize.serialize_create_account_op(w, op)
|
serialize.write_create_account_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarCreatePassiveOfferOp):
|
elif isinstance(op, serialize.StellarCreatePassiveOfferOp):
|
||||||
await layout.confirm_create_passive_offer_op(ctx, op)
|
await layout.confirm_create_passive_offer_op(ctx, op)
|
||||||
serialize.serialize_create_passive_offer_op(w, op)
|
serialize.write_create_passive_offer_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarManageDataOp):
|
elif isinstance(op, serialize.StellarManageDataOp):
|
||||||
await layout.confirm_manage_data_op(ctx, op)
|
await layout.confirm_manage_data_op(ctx, op)
|
||||||
serialize.serialize_manage_data_op(w, op)
|
serialize.write_manage_data_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarManageOfferOp):
|
elif isinstance(op, serialize.StellarManageOfferOp):
|
||||||
await layout.confirm_manage_offer_op(ctx, op)
|
await layout.confirm_manage_offer_op(ctx, op)
|
||||||
serialize.serialize_manage_offer_op(w, op)
|
serialize.write_manage_offer_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarPathPaymentOp):
|
elif isinstance(op, serialize.StellarPathPaymentOp):
|
||||||
await layout.confirm_path_payment_op(ctx, op)
|
await layout.confirm_path_payment_op(ctx, op)
|
||||||
serialize.serialize_path_payment_op(w, op)
|
serialize.write_path_payment_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarPaymentOp):
|
elif isinstance(op, serialize.StellarPaymentOp):
|
||||||
await layout.confirm_payment_op(ctx, op)
|
await layout.confirm_payment_op(ctx, op)
|
||||||
serialize.serialize_payment_op(w, op)
|
serialize.write_payment_op(w, op)
|
||||||
elif isinstance(op, serialize.StellarSetOptionsOp):
|
elif isinstance(op, serialize.StellarSetOptionsOp):
|
||||||
await layout.confirm_set_options_op(ctx, op)
|
await layout.confirm_set_options_op(ctx, op)
|
||||||
serialize.serialize_set_options_op(w, op)
|
serialize.write_set_options_op(w, op)
|
||||||
else:
|
else:
|
||||||
raise ValueError("serialize.Stellar: unknown operation")
|
raise ValueError("Unknown operation")
|
||||||
|
@ -15,42 +15,42 @@ from trezor.wire import ProcessError
|
|||||||
from apps.stellar import consts, writers
|
from apps.stellar import consts, writers
|
||||||
|
|
||||||
|
|
||||||
def serialize_account_merge_op(w, msg: StellarAccountMergeOp):
|
def write_account_merge_op(w, msg: StellarAccountMergeOp):
|
||||||
writers.write_pubkey(w, msg.destination_account)
|
writers.write_pubkey(w, msg.destination_account)
|
||||||
|
|
||||||
|
|
||||||
def serialize_allow_trust_op(w, msg: StellarAllowTrustOp):
|
def write_allow_trust_op(w, msg: StellarAllowTrustOp):
|
||||||
# trustor account (the account being allowed to access the asset)
|
# trustor account (the account being allowed to access the asset)
|
||||||
writers.write_pubkey(w, msg.trusted_account)
|
writers.write_pubkey(w, msg.trusted_account)
|
||||||
writers.write_uint32(w, msg.asset_type)
|
writers.write_uint32(w, msg.asset_type)
|
||||||
_serialize_asset_code(w, msg.asset_type, msg.asset_code)
|
_write_asset_code(w, msg.asset_type, msg.asset_code)
|
||||||
|
|
||||||
writers.write_bool(w, msg.is_authorized)
|
writers.write_bool(w, msg.is_authorized)
|
||||||
|
|
||||||
|
|
||||||
def serialize_bump_sequence_op(w, msg: StellarBumpSequenceOp):
|
def write_bump_sequence_op(w, msg: StellarBumpSequenceOp):
|
||||||
writers.write_uint64(w, msg.bump_to)
|
writers.write_uint64(w, msg.bump_to)
|
||||||
|
|
||||||
|
|
||||||
def serialize_change_trust_op(w, msg: StellarChangeTrustOp):
|
def write_change_trust_op(w, msg: StellarChangeTrustOp):
|
||||||
_serialize_asset(w, msg.asset)
|
_write_asset(w, msg.asset)
|
||||||
writers.write_uint64(w, msg.limit)
|
writers.write_uint64(w, msg.limit)
|
||||||
|
|
||||||
|
|
||||||
def serialize_create_account_op(w, msg: StellarCreateAccountOp):
|
def write_create_account_op(w, msg: StellarCreateAccountOp):
|
||||||
writers.write_pubkey(w, msg.new_account)
|
writers.write_pubkey(w, msg.new_account)
|
||||||
writers.write_uint64(w, msg.starting_balance)
|
writers.write_uint64(w, msg.starting_balance)
|
||||||
|
|
||||||
|
|
||||||
def serialize_create_passive_offer_op(w, msg: StellarCreatePassiveOfferOp):
|
def write_create_passive_offer_op(w, msg: StellarCreatePassiveOfferOp):
|
||||||
_serialize_asset(w, msg.selling_asset)
|
_write_asset(w, msg.selling_asset)
|
||||||
_serialize_asset(w, msg.buying_asset)
|
_write_asset(w, msg.buying_asset)
|
||||||
writers.write_uint64(w, msg.amount)
|
writers.write_uint64(w, msg.amount)
|
||||||
writers.write_uint32(w, msg.price_n)
|
writers.write_uint32(w, msg.price_n)
|
||||||
writers.write_uint32(w, msg.price_d)
|
writers.write_uint32(w, msg.price_d)
|
||||||
|
|
||||||
|
|
||||||
def serialize_manage_data_op(w, msg: StellarManageDataOp):
|
def write_manage_data_op(w, msg: StellarManageDataOp):
|
||||||
if len(msg.key) > 64:
|
if len(msg.key) > 64:
|
||||||
raise ProcessError("Stellar: max length of a key is 64 bytes")
|
raise ProcessError("Stellar: max length of a key is 64 bytes")
|
||||||
writers.write_string(w, msg.key)
|
writers.write_string(w, msg.key)
|
||||||
@ -60,34 +60,34 @@ def serialize_manage_data_op(w, msg: StellarManageDataOp):
|
|||||||
writers.write_bytes(w, msg.value)
|
writers.write_bytes(w, msg.value)
|
||||||
|
|
||||||
|
|
||||||
def serialize_manage_offer_op(w, msg: StellarManageOfferOp):
|
def write_manage_offer_op(w, msg: StellarManageOfferOp):
|
||||||
_serialize_asset(w, msg.selling_asset)
|
_write_asset(w, msg.selling_asset)
|
||||||
_serialize_asset(w, msg.buying_asset)
|
_write_asset(w, msg.buying_asset)
|
||||||
writers.write_uint64(w, msg.amount) # amount to sell
|
writers.write_uint64(w, msg.amount) # amount to sell
|
||||||
writers.write_uint32(w, msg.price_n) # numerator
|
writers.write_uint32(w, msg.price_n) # numerator
|
||||||
writers.write_uint32(w, msg.price_d) # denominator
|
writers.write_uint32(w, msg.price_d) # denominator
|
||||||
writers.write_uint64(w, msg.offer_id)
|
writers.write_uint64(w, msg.offer_id)
|
||||||
|
|
||||||
|
|
||||||
def serialize_path_payment_op(w, msg: StellarPathPaymentOp):
|
def write_path_payment_op(w, msg: StellarPathPaymentOp):
|
||||||
_serialize_asset(w, msg.send_asset)
|
_write_asset(w, msg.send_asset)
|
||||||
writers.write_uint64(w, msg.send_max)
|
writers.write_uint64(w, msg.send_max)
|
||||||
writers.write_pubkey(w, msg.destination_account)
|
writers.write_pubkey(w, msg.destination_account)
|
||||||
|
|
||||||
_serialize_asset(w, msg.destination_asset)
|
_write_asset(w, msg.destination_asset)
|
||||||
writers.write_uint64(w, msg.destination_amount)
|
writers.write_uint64(w, msg.destination_amount)
|
||||||
writers.write_uint32(w, len(msg.paths))
|
writers.write_uint32(w, len(msg.paths))
|
||||||
for p in msg.paths:
|
for p in msg.paths:
|
||||||
_serialize_asset(w, p)
|
_write_asset(w, p)
|
||||||
|
|
||||||
|
|
||||||
def serialize_payment_op(w, msg: StellarPaymentOp):
|
def write_payment_op(w, msg: StellarPaymentOp):
|
||||||
writers.write_pubkey(w, msg.destination_account)
|
writers.write_pubkey(w, msg.destination_account)
|
||||||
_serialize_asset(w, msg.asset)
|
_write_asset(w, msg.asset)
|
||||||
writers.write_uint64(w, msg.amount)
|
writers.write_uint64(w, msg.amount)
|
||||||
|
|
||||||
|
|
||||||
def serialize_set_options_op(w, msg: StellarSetOptionsOp):
|
def write_set_options_op(w, msg: StellarSetOptionsOp):
|
||||||
# inflation destination
|
# inflation destination
|
||||||
writers.write_bool(w, bool(msg.inflation_destination_account))
|
writers.write_bool(w, bool(msg.inflation_destination_account))
|
||||||
if msg.inflation_destination_account:
|
if msg.inflation_destination_account:
|
||||||
@ -136,14 +136,14 @@ def serialize_set_options_op(w, msg: StellarSetOptionsOp):
|
|||||||
writers.write_uint32(w, msg.signer_weight)
|
writers.write_uint32(w, msg.signer_weight)
|
||||||
|
|
||||||
|
|
||||||
def serialize_account(w, source_account: str):
|
def write_account(w, source_account: str):
|
||||||
if source_account is None:
|
if source_account is None:
|
||||||
writers.write_bool(w, False)
|
writers.write_bool(w, False)
|
||||||
return
|
return
|
||||||
writers.write_pubkey(w, source_account)
|
writers.write_pubkey(w, source_account)
|
||||||
|
|
||||||
|
|
||||||
def _serialize_asset_code(w, asset_type: int, asset_code: str):
|
def _write_asset_code(w, asset_type: int, asset_code: str):
|
||||||
code = bytearray(asset_code)
|
code = bytearray(asset_code)
|
||||||
if asset_type == consts.ASSET_TYPE_NATIVE:
|
if asset_type == consts.ASSET_TYPE_NATIVE:
|
||||||
return # nothing is needed
|
return # nothing is needed
|
||||||
@ -157,10 +157,10 @@ def _serialize_asset_code(w, asset_type: int, asset_code: str):
|
|||||||
raise ProcessError("Stellar: invalid asset type")
|
raise ProcessError("Stellar: invalid asset type")
|
||||||
|
|
||||||
|
|
||||||
def _serialize_asset(w, asset: StellarAssetType):
|
def _write_asset(w, asset: StellarAssetType):
|
||||||
if asset is None:
|
if asset is None:
|
||||||
writers.write_uint32(w, 0)
|
writers.write_uint32(w, 0)
|
||||||
return
|
return
|
||||||
writers.write_uint32(w, asset.type)
|
writers.write_uint32(w, asset.type)
|
||||||
_serialize_asset_code(w, asset.type, asset.code)
|
_write_asset_code(w, asset.type, asset.code)
|
||||||
writers.write_pubkey(w, asset.issuer)
|
writers.write_pubkey(w, asset.issuer)
|
||||||
|
@ -9,7 +9,7 @@ from trezor.wire import ProcessError
|
|||||||
|
|
||||||
from apps.common import seed
|
from apps.common import seed
|
||||||
from apps.stellar import consts, helpers, layout, writers
|
from apps.stellar import consts, helpers, layout, writers
|
||||||
from apps.stellar.operations import operation
|
from apps.stellar.operations import process_operation
|
||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg: StellarSignTx):
|
async def sign_tx(ctx, msg: StellarSignTx):
|
||||||
@ -72,7 +72,7 @@ async def _operations(ctx, w: bytearray, num_operations: int):
|
|||||||
writers.write_uint32(w, num_operations)
|
writers.write_uint32(w, num_operations)
|
||||||
for i in range(num_operations):
|
for i in range(num_operations):
|
||||||
op = await ctx.call(StellarTxOpRequest(), *consts.op_wire_types)
|
op = await ctx.call(StellarTxOpRequest(), *consts.op_wire_types)
|
||||||
await operation(ctx, w, op)
|
await process_operation(ctx, w, op)
|
||||||
|
|
||||||
|
|
||||||
async def _memo(ctx, w: bytearray, msg: StellarSignTx):
|
async def _memo(ctx, w: bytearray, msg: StellarSignTx):
|
||||||
|
@ -1,30 +1,22 @@
|
|||||||
import ustruct
|
|
||||||
|
|
||||||
from .helpers import public_key_from_address
|
from .helpers import public_key_from_address
|
||||||
|
|
||||||
|
from apps.common.writers import write_bytes, write_uint32_be, write_uint64_be
|
||||||
|
|
||||||
def write_uint32(w, n: int):
|
write_uint32 = write_uint32_be
|
||||||
write_bytes(w, ustruct.pack(">L", n))
|
write_uint64 = write_uint64_be
|
||||||
|
|
||||||
|
|
||||||
def write_uint64(w, n: int):
|
|
||||||
write_bytes(w, ustruct.pack(">Q", n))
|
|
||||||
|
|
||||||
|
|
||||||
def write_string(w, s: str):
|
def write_string(w, s: str):
|
||||||
write_uint32(w, len(s))
|
buf = s.encode()
|
||||||
write_bytes(w, bytearray(s))
|
write_uint32(w, len(buf))
|
||||||
|
write_bytes(w, buf)
|
||||||
# if len isn't a multiple of 4, add padding bytes
|
# if len isn't a multiple of 4, add padding bytes
|
||||||
reminder = len(s) % 4
|
reminder = len(buf) % 4
|
||||||
if reminder:
|
if reminder:
|
||||||
write_bytes(w, bytearray([0] * (4 - reminder)))
|
write_bytes(w, bytes([0] * (4 - reminder)))
|
||||||
|
|
||||||
|
|
||||||
def write_bytes(w, buf: bytearray):
|
def write_bool(w, val: bool):
|
||||||
w.extend(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def write_bool(w, val: True):
|
|
||||||
if val:
|
if val:
|
||||||
write_uint32(w, 1)
|
write_uint32(w, 1)
|
||||||
else:
|
else:
|
||||||
@ -34,5 +26,4 @@ def write_bool(w, val: True):
|
|||||||
def write_pubkey(w, address: str):
|
def write_pubkey(w, address: str):
|
||||||
# first 4 bytes of an address are the type, there's only one type (0)
|
# first 4 bytes of an address are the type, there's only one type (0)
|
||||||
write_uint32(w, 0)
|
write_uint32(w, 0)
|
||||||
pubkey = public_key_from_address(address)
|
write_bytes(w, public_key_from_address(address))
|
||||||
write_bytes(w, bytearray(pubkey))
|
|
||||||
|
@ -13,7 +13,7 @@ from apps.wallet.sign_tx.scripts import output_script_multisig, output_script_p2
|
|||||||
from apps.wallet.sign_tx.writers import (
|
from apps.wallet.sign_tx.writers import (
|
||||||
get_tx_hash,
|
get_tx_hash,
|
||||||
write_bytes,
|
write_bytes,
|
||||||
write_bytes_rev,
|
write_bytes_reversed,
|
||||||
write_tx_output,
|
write_tx_output,
|
||||||
write_uint32,
|
write_uint32,
|
||||||
write_uint64,
|
write_uint64,
|
||||||
@ -34,7 +34,7 @@ class Zip143:
|
|||||||
self.h_outputs = HashWriter(blake2b, outlen=32, personal=b"ZcashOutputsHash")
|
self.h_outputs = HashWriter(blake2b, outlen=32, personal=b"ZcashOutputsHash")
|
||||||
|
|
||||||
def add_prevouts(self, txi: TxInputType):
|
def add_prevouts(self, txi: TxInputType):
|
||||||
write_bytes_rev(self.h_prevouts, txi.prev_hash)
|
write_bytes_reversed(self.h_prevouts, txi.prev_hash)
|
||||||
write_uint32(self.h_prevouts, txi.prev_index)
|
write_uint32(self.h_prevouts, txi.prev_index)
|
||||||
|
|
||||||
def add_sequence(self, txi: TxInputType):
|
def add_sequence(self, txi: TxInputType):
|
||||||
@ -78,7 +78,7 @@ class Zip143:
|
|||||||
write_uint32(h_preimage, tx.expiry) # 8. expiryHeight
|
write_uint32(h_preimage, tx.expiry) # 8. expiryHeight
|
||||||
write_uint32(h_preimage, sighash) # 9. nHashType
|
write_uint32(h_preimage, sighash) # 9. nHashType
|
||||||
|
|
||||||
write_bytes_rev(h_preimage, txi.prev_hash) # 10a. outpoint
|
write_bytes_reversed(h_preimage, txi.prev_hash) # 10a. outpoint
|
||||||
write_uint32(h_preimage, txi.prev_index)
|
write_uint32(h_preimage, txi.prev_index)
|
||||||
|
|
||||||
script_code = self.derive_script_code(txi, pubkeyhash) # 10b. scriptCode
|
script_code = self.derive_script_code(txi, pubkeyhash) # 10b. scriptCode
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from trezor.crypto.hashlib import ripemd160, sha256
|
from trezor.crypto.hashlib import ripemd160, sha256
|
||||||
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
|
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
|
||||||
|
|
||||||
|
from apps.common.writers import empty_bytearray
|
||||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
||||||
from apps.wallet.sign_tx.writers import (
|
from apps.wallet.sign_tx.writers import (
|
||||||
bytearray_with_cap,
|
|
||||||
write_bytes,
|
write_bytes,
|
||||||
write_op_push,
|
write_op_push,
|
||||||
write_scriptnum,
|
write_scriptnum,
|
||||||
@ -23,7 +23,7 @@ class ScriptsError(ValueError):
|
|||||||
def input_script_p2pkh_or_p2sh(
|
def input_script_p2pkh_or_p2sh(
|
||||||
pubkey: bytes, signature: bytes, sighash: int
|
pubkey: bytes, signature: bytes, sighash: int
|
||||||
) -> bytearray:
|
) -> bytearray:
|
||||||
w = bytearray_with_cap(5 + len(signature) + 1 + 5 + len(pubkey))
|
w = empty_bytearray(5 + len(signature) + 1 + 5 + len(pubkey))
|
||||||
append_signature(w, signature, sighash)
|
append_signature(w, signature, sighash)
|
||||||
append_pubkey(w, pubkey)
|
append_pubkey(w, pubkey)
|
||||||
return w
|
return w
|
||||||
@ -87,7 +87,7 @@ def output_script_native_p2wpkh_or_p2wsh(witprog: bytes) -> bytearray:
|
|||||||
# 00 14 <20-byte-key-hash>
|
# 00 14 <20-byte-key-hash>
|
||||||
# 00 20 <32-byte-script-hash>
|
# 00 20 <32-byte-script-hash>
|
||||||
|
|
||||||
w = bytearray_with_cap(3 + len(witprog))
|
w = empty_bytearray(3 + len(witprog))
|
||||||
w.append(0x00) # witness version byte
|
w.append(0x00) # witness version byte
|
||||||
w.append(len(witprog)) # pub key hash length is 20 (P2WPKH) or 32 (P2WSH) bytes
|
w.append(len(witprog)) # pub key hash length is 20 (P2WPKH) or 32 (P2WSH) bytes
|
||||||
write_bytes(w, witprog) # pub key hash
|
write_bytes(w, witprog) # pub key hash
|
||||||
@ -106,7 +106,7 @@ def input_script_p2wpkh_in_p2sh(pubkeyhash: bytes) -> bytearray:
|
|||||||
# 16 00 14 <pubkeyhash>
|
# 16 00 14 <pubkeyhash>
|
||||||
# Signature is moved to the witness.
|
# Signature is moved to the witness.
|
||||||
|
|
||||||
w = bytearray_with_cap(3 + len(pubkeyhash))
|
w = empty_bytearray(3 + len(pubkeyhash))
|
||||||
w.append(0x16) # length of the data
|
w.append(0x16) # length of the data
|
||||||
w.append(0x00) # witness version byte
|
w.append(0x00) # witness version byte
|
||||||
w.append(0x14) # P2WPKH witness program (pub key hash length)
|
w.append(0x14) # P2WPKH witness program (pub key hash length)
|
||||||
@ -129,7 +129,7 @@ def input_script_p2wsh_in_p2sh(script_hash: bytes) -> bytearray:
|
|||||||
if len(script_hash) != 32:
|
if len(script_hash) != 32:
|
||||||
raise ScriptsError("Redeem script hash should be 32 bytes long")
|
raise ScriptsError("Redeem script hash should be 32 bytes long")
|
||||||
|
|
||||||
w = bytearray_with_cap(3 + len(script_hash))
|
w = empty_bytearray(3 + len(script_hash))
|
||||||
w.append(0x22) # length of the data
|
w.append(0x22) # length of the data
|
||||||
w.append(0x00) # witness version byte
|
w.append(0x00) # witness version byte
|
||||||
w.append(0x20) # P2WSH witness program (redeem script hash length)
|
w.append(0x20) # P2WSH witness program (redeem script hash length)
|
||||||
@ -142,7 +142,7 @@ def input_script_p2wsh_in_p2sh(script_hash: bytes) -> bytearray:
|
|||||||
|
|
||||||
|
|
||||||
def witness_p2wpkh(signature: bytes, pubkey: bytes, sighash: int):
|
def witness_p2wpkh(signature: bytes, pubkey: bytes, sighash: int):
|
||||||
w = bytearray_with_cap(1 + 5 + len(signature) + 1 + 5 + len(pubkey))
|
w = empty_bytearray(1 + 5 + len(signature) + 1 + 5 + len(pubkey))
|
||||||
write_varint(w, 0x02) # num of segwit items, in P2WPKH it's always 2
|
write_varint(w, 0x02) # num of segwit items, in P2WPKH it's always 2
|
||||||
append_signature(w, signature, sighash)
|
append_signature(w, signature, sighash)
|
||||||
append_pubkey(w, pubkey)
|
append_pubkey(w, pubkey)
|
||||||
@ -239,7 +239,7 @@ def output_script_multisig(pubkeys, m: int) -> bytearray:
|
|||||||
|
|
||||||
|
|
||||||
def output_script_paytoopreturn(data: bytes) -> bytearray:
|
def output_script_paytoopreturn(data: bytes) -> bytearray:
|
||||||
w = bytearray_with_cap(1 + 5 + len(data))
|
w = empty_bytearray(1 + 5 + len(data))
|
||||||
w.append(0x6A) # OP_RETURN
|
w.append(0x6A) # OP_RETURN
|
||||||
write_op_push(w, len(data))
|
write_op_push(w, len(data))
|
||||||
w.extend(data)
|
w.extend(data)
|
||||||
|
@ -11,7 +11,7 @@ from apps.wallet.sign_tx.scripts import output_script_multisig, output_script_p2
|
|||||||
from apps.wallet.sign_tx.writers import (
|
from apps.wallet.sign_tx.writers import (
|
||||||
get_tx_hash,
|
get_tx_hash,
|
||||||
write_bytes,
|
write_bytes,
|
||||||
write_bytes_rev,
|
write_bytes_reversed,
|
||||||
write_tx_output,
|
write_tx_output,
|
||||||
write_uint32,
|
write_uint32,
|
||||||
write_uint64,
|
write_uint64,
|
||||||
@ -30,7 +30,7 @@ class Bip143:
|
|||||||
self.h_outputs = HashWriter(sha256)
|
self.h_outputs = HashWriter(sha256)
|
||||||
|
|
||||||
def add_prevouts(self, txi: TxInputType):
|
def add_prevouts(self, txi: TxInputType):
|
||||||
write_bytes_rev(self.h_prevouts, txi.prev_hash)
|
write_bytes_reversed(self.h_prevouts, txi.prev_hash)
|
||||||
write_uint32(self.h_prevouts, txi.prev_index)
|
write_uint32(self.h_prevouts, txi.prev_index)
|
||||||
|
|
||||||
def add_sequence(self, txi: TxInputType):
|
def add_sequence(self, txi: TxInputType):
|
||||||
@ -64,7 +64,7 @@ class Bip143:
|
|||||||
write_bytes(h_preimage, bytearray(self.get_prevouts_hash(coin))) # hashPrevouts
|
write_bytes(h_preimage, bytearray(self.get_prevouts_hash(coin))) # hashPrevouts
|
||||||
write_bytes(h_preimage, bytearray(self.get_sequence_hash(coin))) # hashSequence
|
write_bytes(h_preimage, bytearray(self.get_sequence_hash(coin))) # hashSequence
|
||||||
|
|
||||||
write_bytes_rev(h_preimage, txi.prev_hash) # outpoint
|
write_bytes_reversed(h_preimage, txi.prev_hash) # outpoint
|
||||||
write_uint32(h_preimage, txi.prev_index) # outpoint
|
write_uint32(h_preimage, txi.prev_index) # outpoint
|
||||||
|
|
||||||
script_code = self.derive_script_code(txi, pubkeyhash) # scriptCode
|
script_code = self.derive_script_code(txi, pubkeyhash) # scriptCode
|
||||||
|
@ -10,6 +10,7 @@ from trezor.utils import HashWriter
|
|||||||
|
|
||||||
from apps.common import address_type, coins
|
from apps.common import address_type, coins
|
||||||
from apps.common.coininfo import CoinInfo
|
from apps.common.coininfo import CoinInfo
|
||||||
|
from apps.common.writers import empty_bytearray
|
||||||
from apps.wallet.sign_tx import progress
|
from apps.wallet.sign_tx import progress
|
||||||
from apps.wallet.sign_tx.addresses import *
|
from apps.wallet.sign_tx.addresses import *
|
||||||
from apps.wallet.sign_tx.helpers import *
|
from apps.wallet.sign_tx.helpers import *
|
||||||
@ -206,7 +207,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|||||||
key_sign_pub = key_sign.public_key()
|
key_sign_pub = key_sign.public_key()
|
||||||
txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub)
|
txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub)
|
||||||
|
|
||||||
w_txi = bytearray_with_cap(
|
w_txi = empty_bytearray(
|
||||||
7 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4
|
7 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4
|
||||||
)
|
)
|
||||||
if i_sign == 0: # serializing first input => prepend headers
|
if i_sign == 0: # serializing first input => prepend headers
|
||||||
@ -248,7 +249,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|||||||
txi_sign.script_sig = input_derive_script(
|
txi_sign.script_sig = input_derive_script(
|
||||||
coin, txi_sign, key_sign_pub, signature
|
coin, txi_sign, key_sign_pub, signature
|
||||||
)
|
)
|
||||||
w_txi_sign = bytearray_with_cap(
|
w_txi_sign = empty_bytearray(
|
||||||
5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4
|
5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4
|
||||||
)
|
)
|
||||||
if i_sign == 0: # serializing first input => prepend headers
|
if i_sign == 0: # serializing first input => prepend headers
|
||||||
@ -344,7 +345,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|||||||
txi_sign.script_sig = input_derive_script(
|
txi_sign.script_sig = input_derive_script(
|
||||||
coin, txi_sign, key_sign_pub, signature
|
coin, txi_sign, key_sign_pub, signature
|
||||||
)
|
)
|
||||||
w_txi_sign = bytearray_with_cap(
|
w_txi_sign = empty_bytearray(
|
||||||
5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4
|
5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4
|
||||||
)
|
)
|
||||||
if i_sign == 0: # serializing first input => prepend headers
|
if i_sign == 0: # serializing first input => prepend headers
|
||||||
@ -362,7 +363,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|||||||
txo_bin.script_pubkey = output_derive_script(txo, coin, root)
|
txo_bin.script_pubkey = output_derive_script(txo, coin, root)
|
||||||
|
|
||||||
# serialize output
|
# serialize output
|
||||||
w_txo_bin = bytearray_with_cap(5 + 8 + 5 + len(txo_bin.script_pubkey) + 4)
|
w_txo_bin = empty_bytearray(5 + 8 + 5 + len(txo_bin.script_pubkey) + 4)
|
||||||
if o == 0: # serializing first output => prepend outputs count
|
if o == 0: # serializing first output => prepend outputs count
|
||||||
write_varint(w_txo_bin, tx.outputs_count)
|
write_varint(w_txo_bin, tx.outputs_count)
|
||||||
write_tx_output(w_txo_bin, txo_bin)
|
write_tx_output(w_txo_bin, txo_bin)
|
||||||
|
@ -2,12 +2,19 @@ from trezor.crypto.hashlib import sha256
|
|||||||
from trezor.messages.TxInputType import TxInputType
|
from trezor.messages.TxInputType import TxInputType
|
||||||
from trezor.messages.TxOutputBinType import TxOutputBinType
|
from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||||
|
|
||||||
# TX Serialization
|
from apps.common.writers import (
|
||||||
# ===
|
write_bytes,
|
||||||
|
write_bytes_reversed,
|
||||||
|
write_uint32_le,
|
||||||
|
write_uint64_le,
|
||||||
|
)
|
||||||
|
|
||||||
|
write_uint32 = write_uint32_le
|
||||||
|
write_uint64 = write_uint64_le
|
||||||
|
|
||||||
|
|
||||||
def write_tx_input(w, i: TxInputType):
|
def write_tx_input(w, i: TxInputType):
|
||||||
write_bytes_rev(w, i.prev_hash)
|
write_bytes_reversed(w, i.prev_hash)
|
||||||
write_uint32(w, i.prev_index)
|
write_uint32(w, i.prev_index)
|
||||||
write_varint(w, len(i.script_sig))
|
write_varint(w, len(i.script_sig))
|
||||||
write_bytes(w, i.script_sig)
|
write_bytes(w, i.script_sig)
|
||||||
@ -50,10 +57,6 @@ def write_op_push(w, n: int):
|
|||||||
w.append((n >> 24) & 0xFF)
|
w.append((n >> 24) & 0xFF)
|
||||||
|
|
||||||
|
|
||||||
# Buffer IO & Serialization
|
|
||||||
# ===
|
|
||||||
|
|
||||||
|
|
||||||
def write_varint(w, n: int):
|
def write_varint(w, n: int):
|
||||||
assert n >= 0 and n <= 0xFFFFFFFF
|
assert n >= 0 and n <= 0xFFFFFFFF
|
||||||
if n < 253:
|
if n < 253:
|
||||||
@ -92,44 +95,6 @@ def write_scriptnum(w, n: int):
|
|||||||
w.append((n >> 24) & 0xFF)
|
w.append((n >> 24) & 0xFF)
|
||||||
|
|
||||||
|
|
||||||
def write_uint32(w, n: int):
|
|
||||||
assert n >= 0 and n <= 0xFFFFFFFF
|
|
||||||
w.append(n & 0xFF)
|
|
||||||
w.append((n >> 8) & 0xFF)
|
|
||||||
w.append((n >> 16) & 0xFF)
|
|
||||||
w.append((n >> 24) & 0xFF)
|
|
||||||
|
|
||||||
|
|
||||||
def write_uint64(w, n: int):
|
|
||||||
assert n >= 0 and n <= 0xFFFFFFFFFFFFFFFF
|
|
||||||
w.append(n & 0xFF)
|
|
||||||
w.append((n >> 8) & 0xFF)
|
|
||||||
w.append((n >> 16) & 0xFF)
|
|
||||||
w.append((n >> 24) & 0xFF)
|
|
||||||
w.append((n >> 32) & 0xFF)
|
|
||||||
w.append((n >> 40) & 0xFF)
|
|
||||||
w.append((n >> 48) & 0xFF)
|
|
||||||
w.append((n >> 56) & 0xFF)
|
|
||||||
|
|
||||||
|
|
||||||
def write_bytes(w, buf: bytearray):
|
|
||||||
w.extend(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def write_bytes_rev(w, buf: bytearray):
|
|
||||||
w.extend(bytearray(reversed(buf)))
|
|
||||||
|
|
||||||
|
|
||||||
def bytearray_with_cap(cap: int) -> bytearray:
|
|
||||||
b = bytearray(cap)
|
|
||||||
b[:] = bytes()
|
|
||||||
return b
|
|
||||||
|
|
||||||
|
|
||||||
# Hashes
|
|
||||||
# ===
|
|
||||||
|
|
||||||
|
|
||||||
def get_tx_hash(w, double: bool = False, reverse: bool = False) -> bytes:
|
def get_tx_hash(w, double: bool = False, reverse: bool = False) -> bytes:
|
||||||
d = w.get_digest()
|
d = w.get_digest()
|
||||||
if double:
|
if double:
|
||||||
|
@ -1,85 +1,159 @@
|
|||||||
from common import *
|
from common import *
|
||||||
|
from trezor.crypto import hashlib
|
||||||
|
from trezor.messages.NEMAggregateModification import NEMAggregateModification
|
||||||
|
from trezor.messages.NEMCosignatoryModification import NEMCosignatoryModification
|
||||||
|
from trezor.messages.NEMSignTx import NEMSignTx
|
||||||
|
from trezor.messages.NEMTransactionCommon import NEMTransactionCommon
|
||||||
|
|
||||||
from apps.nem.helpers import *
|
from apps.nem.helpers import *
|
||||||
from apps.nem.multisig import *
|
from apps.nem.multisig import *
|
||||||
from apps.nem.multisig.serialize import *
|
from apps.nem.multisig.serialize import *
|
||||||
|
|
||||||
from trezor.crypto import hashlib
|
|
||||||
from trezor.messages.NEMSignTx import NEMSignTx
|
|
||||||
from trezor.messages.NEMAggregateModification import NEMAggregateModification
|
|
||||||
from trezor.messages.NEMCosignatoryModification import NEMCosignatoryModification
|
|
||||||
from trezor.messages.NEMTransactionCommon import NEMTransactionCommon
|
|
||||||
|
|
||||||
|
|
||||||
class TestNemMultisigAggregateModification(unittest.TestCase):
|
class TestNemMultisigAggregateModification(unittest.TestCase):
|
||||||
|
|
||||||
def test_nem_transaction_aggregate_modification(self):
|
def test_nem_transaction_aggregate_modification(self):
|
||||||
# http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2
|
# http://bob.nem.ninja:8765/#/aggregate/6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2
|
||||||
m = _create_msg(NEM_NETWORK_TESTNET,
|
m = _create_msg(NEM_NETWORK_TESTNET, 0, 22000000, 0, 2, 0)
|
||||||
0,
|
t = serialize_aggregate_modification(
|
||||||
22000000,
|
m.transaction,
|
||||||
0,
|
m.aggregate_modification,
|
||||||
2,
|
unhexlify(
|
||||||
0)
|
"462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"
|
||||||
t = serialize_aggregate_modification(m.transaction, m.aggregate_modification, unhexlify("462ee976890916e54fa825d26bdd0235f5eb5b6a143c199ab0ae5ee9328e08ce"))
|
),
|
||||||
|
)
|
||||||
|
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
write_cosignatory_modification(
|
||||||
"994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"))
|
t,
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
1,
|
||||||
"c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"))
|
unhexlify(
|
||||||
|
"994793ba1c789fa9bdea918afc9b06e2d0309beb1081ac5b6952991e4defd324"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_cosignatory_modification(
|
||||||
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"c54d6e33ed1446eedd7f7a80a588dd01857f723687a09200c1917d5524752f8b"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(hashlib.sha3_256(t, keccak=True).digest(),
|
self.assertEqual(
|
||||||
unhexlify("6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"))
|
hashlib.sha3_256(t, keccak=True).digest(),
|
||||||
|
unhexlify(
|
||||||
|
"6a55471b17159e5b6cd579c421e95a4e39d92e3f78b0a55ee337e785a601d3a2"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c
|
# http://chain.nem.ninja/#/aggregate/cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c
|
||||||
m = _create_msg(NEM_NETWORK_MAINNET,
|
m = _create_msg(NEM_NETWORK_MAINNET, 0, 40000000, 0, 5, 0)
|
||||||
0,
|
t = serialize_aggregate_modification(
|
||||||
40000000,
|
m.transaction,
|
||||||
0,
|
m.aggregate_modification,
|
||||||
5,
|
unhexlify(
|
||||||
0)
|
"f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"
|
||||||
t = serialize_aggregate_modification(m.transaction, m.aggregate_modification, unhexlify("f41b99320549741c5cce42d9e4bb836d98c50ed5415d0c3c2912d1bb50e6a0e5"))
|
),
|
||||||
|
)
|
||||||
|
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
write_cosignatory_modification(
|
||||||
"1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"))
|
t,
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
1,
|
||||||
"f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"))
|
unhexlify(
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
"1fbdbdde28daf828245e4533765726f0b7790e0b7146e2ce205df3e86366980b"
|
||||||
"826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"))
|
),
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
)
|
||||||
"719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"))
|
write_cosignatory_modification(
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
t,
|
||||||
"43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"))
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"f94e8702eb1943b23570b1b83be1b81536df35538978820e98bfce8f999e2d37"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_cosignatory_modification(
|
||||||
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"826cedee421ff66e708858c17815fcd831a4bb68e3d8956299334e9e24380ba8"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_cosignatory_modification(
|
||||||
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"719862cd7d0f4e875a6a0274c9a1738f38f40ad9944179006a54c34724c1274d"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_cosignatory_modification(
|
||||||
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"43aa69177018fc3e2bdbeb259c81cddf24be50eef9c5386db51d82386c41475a"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(hashlib.sha3_256(t, keccak=True).digest(),
|
self.assertEqual(
|
||||||
unhexlify("cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"))
|
hashlib.sha3_256(t, keccak=True).digest(),
|
||||||
|
unhexlify(
|
||||||
|
"cc64ca69bfa95db2ff7ac1e21fe6d27ece189c603200ebc9778d8bb80ca25c3c"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_nem_transaction_aggregate_modification_relative_change(self):
|
def test_nem_transaction_aggregate_modification_relative_change(self):
|
||||||
# http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584
|
# http://bob.nem.ninja:8765/#/aggregate/1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584
|
||||||
m = _create_msg(NEM_NETWORK_TESTNET,
|
m = _create_msg(NEM_NETWORK_TESTNET, 6542254, 40000000, 6545854, 4, 2)
|
||||||
6542254,
|
t = serialize_aggregate_modification(
|
||||||
40000000,
|
m.transaction,
|
||||||
6545854,
|
m.aggregate_modification,
|
||||||
4,
|
unhexlify(
|
||||||
2)
|
"6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"
|
||||||
t = serialize_aggregate_modification(m.transaction, m.aggregate_modification, unhexlify("6bf7849c1eec6a2002995cc457dc00c4e29bad5c88de63f51e42dfdcd7b2131d"))
|
),
|
||||||
|
)
|
||||||
|
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
write_cosignatory_modification(
|
||||||
"5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"))
|
t,
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
1,
|
||||||
"9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"))
|
unhexlify(
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
"5f53d076c8c3ec3110b98364bc423092c3ec2be2b1b3c40fd8ab68d54fa39295"
|
||||||
"94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"))
|
),
|
||||||
serialize_cosignatory_modification(t, 1, unhexlify(
|
)
|
||||||
"d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"))
|
write_cosignatory_modification(
|
||||||
serialize_minimum_cosignatories(t, 2)
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"9eb199c2b4d406f64cb7aa5b2b0815264b56ba8fe44d558a6cb423a31a33c4c2"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_cosignatory_modification(
|
||||||
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"94b2323dab23a3faba24fa6ddda0ece4fbb06acfedd74e76ad9fae38d006882b"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_cosignatory_modification(
|
||||||
|
t,
|
||||||
|
1,
|
||||||
|
unhexlify(
|
||||||
|
"d88c6ee2a2cd3929d0d76b6b14ecb549d21296ab196a2b3a4cb2536bcce32e87"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
write_minimum_cosignatories(t, 2)
|
||||||
|
|
||||||
self.assertEqual(hashlib.sha3_256(t, keccak=True).digest(),
|
self.assertEqual(
|
||||||
unhexlify("1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"))
|
hashlib.sha3_256(t, keccak=True).digest(),
|
||||||
|
unhexlify(
|
||||||
|
"1fbdae5ba753e68af270930413ae90f671eb8ab58988116684bac0abd5726584"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _create_msg(network: int, timestamp: int, fee: int, deadline: int,
|
def _create_msg(
|
||||||
modifications: int, relative_change: int):
|
network: int,
|
||||||
|
timestamp: int,
|
||||||
|
fee: int,
|
||||||
|
deadline: int,
|
||||||
|
modifications: int,
|
||||||
|
relative_change: int,
|
||||||
|
):
|
||||||
m = NEMSignTx()
|
m = NEMSignTx()
|
||||||
m.transaction = NEMTransactionCommon()
|
m.transaction = NEMTransactionCommon()
|
||||||
m.transaction.network = network
|
m.transaction.network = network
|
||||||
@ -94,5 +168,5 @@ def _create_msg(network: int, timestamp: int, fee: int, deadline: int,
|
|||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -24,7 +24,7 @@ class TestNemMultisig(unittest.TestCase):
|
|||||||
0)
|
0)
|
||||||
base_tx = serialize_aggregate_modification(m.transaction, m.aggregate_modification, unhexlify("abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"))
|
base_tx = serialize_aggregate_modification(m.transaction, m.aggregate_modification, unhexlify("abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac"))
|
||||||
|
|
||||||
base_tx = serialize_cosignatory_modification(base_tx, 2, unhexlify("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))
|
base_tx = write_cosignatory_modification(base_tx, 2, unhexlify("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3"))
|
||||||
m = _create_common_msg(NEM_NETWORK_TESTNET,
|
m = _create_common_msg(NEM_NETWORK_TESTNET,
|
||||||
3939039,
|
3939039,
|
||||||
6000000,
|
6000000,
|
||||||
|
@ -1,77 +1,98 @@
|
|||||||
from common import *
|
from common import *
|
||||||
from apps.ripple.serialize import serialize
|
|
||||||
from apps.ripple.serialize import serialize_amount
|
|
||||||
from apps.ripple.sign_tx import get_network_prefix
|
|
||||||
from trezor.messages.RippleSignTx import RippleSignTx
|
|
||||||
from trezor.messages.RipplePayment import RipplePayment
|
from trezor.messages.RipplePayment import RipplePayment
|
||||||
|
from trezor.messages.RippleSignTx import RippleSignTx
|
||||||
|
|
||||||
|
from apps.ripple.serialize import serialize, serialize_amount
|
||||||
|
from apps.ripple.sign_tx import get_network_prefix
|
||||||
|
|
||||||
|
|
||||||
class TestRippleSerializer(unittest.TestCase):
|
class TestRippleSerializer(unittest.TestCase):
|
||||||
|
|
||||||
def test_amount(self):
|
def test_amount(self):
|
||||||
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L2494
|
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L2494
|
||||||
assert serialize_amount(0) == unhexlify('4000000000000000')
|
assert serialize_amount(0) == unhexlify("4000000000000000")
|
||||||
assert serialize_amount(1) == unhexlify('4000000000000001')
|
assert serialize_amount(1) == unhexlify("4000000000000001")
|
||||||
assert serialize_amount(93493429243) == unhexlify('40000015c4a483fb')
|
assert serialize_amount(93493429243) == unhexlify("40000015c4a483fb")
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
serialize_amount(1000000000000000000) # too large
|
serialize_amount(1000000000000000000) # too large
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
serialize_amount(-1) # negative not supported
|
serialize_amount(-1) # negative not supported
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(Exception):
|
||||||
serialize_amount(1.1) # float numbers not supported
|
serialize_amount(1.1) # float numbers not supported
|
||||||
|
|
||||||
def test_transactions(self):
|
def test_transactions(self):
|
||||||
# from https://github.com/miracle2k/ripple-python
|
# from https://github.com/miracle2k/ripple-python
|
||||||
source_address = 'r3P9vH81KBayazSTrQj6S25jW6kDb779Gi'
|
source_address = "r3P9vH81KBayazSTrQj6S25jW6kDb779Gi"
|
||||||
payment = RipplePayment(200000000, 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV')
|
payment = RipplePayment(200000000, "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV")
|
||||||
common = RippleSignTx(None, 10, None, 1, None, payment)
|
common = RippleSignTx(None, 10, None, 1, None, payment)
|
||||||
assert serialize(common, source_address) == unhexlify('120000240000000161400000000bebc20068400000000000000a811450f97a072f1c4357f1ad84566a609479d927c9428314550fc62003e785dc231a1058a05e56e3f09cf4e6')
|
assert serialize(common, source_address) == unhexlify(
|
||||||
|
"120000240000000161400000000bebc20068400000000000000a811450f97a072f1c4357f1ad84566a609479d927c9428314550fc62003e785dc231a1058a05e56e3f09cf4e6"
|
||||||
|
)
|
||||||
|
|
||||||
source_address = 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV'
|
source_address = "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV"
|
||||||
payment = RipplePayment(1, 'r3P9vH81KBayazSTrQj6S25jW6kDb779Gi')
|
payment = RipplePayment(1, "r3P9vH81KBayazSTrQj6S25jW6kDb779Gi")
|
||||||
common = RippleSignTx(None, 99, None, 99, None, payment)
|
common = RippleSignTx(None, 99, None, 99, None, payment)
|
||||||
assert serialize(common, source_address) == unhexlify('12000024000000636140000000000000016840000000000000638114550fc62003e785dc231a1058a05e56e3f09cf4e6831450f97a072f1c4357f1ad84566a609479d927c942')
|
assert serialize(common, source_address) == unhexlify(
|
||||||
|
"12000024000000636140000000000000016840000000000000638114550fc62003e785dc231a1058a05e56e3f09cf4e6831450f97a072f1c4357f1ad84566a609479d927c942"
|
||||||
|
)
|
||||||
|
|
||||||
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L1579
|
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L1579
|
||||||
source_address = 'r9TeThyi5xiuUUrFjtPKZiHcDxs7K9H6Rb'
|
source_address = "r9TeThyi5xiuUUrFjtPKZiHcDxs7K9H6Rb"
|
||||||
payment = RipplePayment(25000000, 'r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C')
|
payment = RipplePayment(25000000, "r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C")
|
||||||
common = RippleSignTx(None, 10, 0, 2, None, payment)
|
common = RippleSignTx(None, 10, 0, 2, None, payment)
|
||||||
assert serialize(common, source_address) == unhexlify('120000220000000024000000026140000000017d784068400000000000000a81145ccb151f6e9d603f394ae778acf10d3bece874f68314e851bbbe79e328e43d68f43445368133df5fba5a')
|
assert serialize(common, source_address) == unhexlify(
|
||||||
|
"120000220000000024000000026140000000017d784068400000000000000a81145ccb151f6e9d603f394ae778acf10d3bece874f68314e851bbbe79e328e43d68f43445368133df5fba5a"
|
||||||
|
)
|
||||||
|
|
||||||
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L1651
|
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L1651
|
||||||
source_address = 'rGWTUVmm1fB5QUjMYn8KfnyrFNgDiD9H9e'
|
source_address = "rGWTUVmm1fB5QUjMYn8KfnyrFNgDiD9H9e"
|
||||||
payment = RipplePayment(200000, 'rw71Qs1UYQrSQ9hSgRohqNNQcyjCCfffkQ')
|
payment = RipplePayment(200000, "rw71Qs1UYQrSQ9hSgRohqNNQcyjCCfffkQ")
|
||||||
common = RippleSignTx(None, 15, 0, 144, None, payment)
|
common = RippleSignTx(None, 15, 0, 144, None, payment)
|
||||||
# 201b005ee9ba removed from the test vector because last ledger sequence is not supported
|
# 201b005ee9ba removed from the test vector because last ledger sequence is not supported
|
||||||
assert serialize(common, source_address) == unhexlify('12000022000000002400000090614000000000030d4068400000000000000f8114aa1bd19d9e87be8069fdbf6843653c43837c03c6831467fe6ec28e0464dd24fb2d62a492aac697cfad02')
|
assert serialize(common, source_address) == unhexlify(
|
||||||
|
"12000022000000002400000090614000000000030d4068400000000000000f8114aa1bd19d9e87be8069fdbf6843653c43837c03c6831467fe6ec28e0464dd24fb2d62a492aac697cfad02"
|
||||||
|
)
|
||||||
|
|
||||||
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L1732
|
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/fixtures/data-driven-tests.json#L1732
|
||||||
source_address = 'r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C'
|
source_address = "r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C"
|
||||||
payment = RipplePayment(25000000, 'rBqSFEFg2B6GBMobtxnU1eLA1zbNC9NDGM')
|
payment = RipplePayment(25000000, "rBqSFEFg2B6GBMobtxnU1eLA1zbNC9NDGM")
|
||||||
common = RippleSignTx(None, 12, 0, 1, None, payment)
|
common = RippleSignTx(None, 12, 0, 1, None, payment)
|
||||||
# 2ef72d50ca removed from the test vector because destination tag is not supported
|
# 2ef72d50ca removed from the test vector because destination tag is not supported
|
||||||
assert serialize(common, source_address) == unhexlify('120000220000000024000000016140000000017d784068400000000000000c8114e851bbbe79e328e43d68f43445368133df5fba5a831476dac5e814cd4aa74142c3ab45e69a900e637aa2')
|
assert serialize(common, source_address) == unhexlify(
|
||||||
|
"120000220000000024000000016140000000017d784068400000000000000c8114e851bbbe79e328e43d68f43445368133df5fba5a831476dac5e814cd4aa74142c3ab45e69a900e637aa2"
|
||||||
|
)
|
||||||
|
|
||||||
def test_transactions_for_signing(self):
|
def test_transactions_for_signing(self):
|
||||||
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/signing-data-encoding-test.js
|
# https://github.com/ripple/ripple-binary-codec/blob/4581f1b41e712f545ba08be15e188a557c731ecf/test/signing-data-encoding-test.js
|
||||||
source_address = 'r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ'
|
source_address = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ"
|
||||||
payment = RipplePayment(1000, 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
|
payment = RipplePayment(1000, "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
|
||||||
common = RippleSignTx(None, 10, 2147483648, 1, None, payment)
|
common = RippleSignTx(None, 10, 2147483648, 1, None, payment)
|
||||||
|
|
||||||
tx = serialize(common, source_address, pubkey=unhexlify('ed5f5ac8b98974a3ca843326d9b88cebd0560177b973ee0b149f782cfaa06dc66a'))
|
tx = serialize(
|
||||||
|
common,
|
||||||
|
source_address,
|
||||||
|
pubkey=unhexlify(
|
||||||
|
"ed5f5ac8b98974a3ca843326d9b88cebd0560177b973ee0b149f782cfaa06dc66a"
|
||||||
|
),
|
||||||
|
)
|
||||||
tx = get_network_prefix() + tx
|
tx = get_network_prefix() + tx
|
||||||
|
|
||||||
assert tx[0:4] == unhexlify('53545800') # signing prefix
|
assert tx[0:4] == unhexlify("53545800") # signing prefix
|
||||||
assert tx[4:7] == unhexlify('120000') # transaction type
|
assert tx[4:7] == unhexlify("120000") # transaction type
|
||||||
assert tx[7:12] == unhexlify('2280000000') # flags
|
assert tx[7:12] == unhexlify("2280000000") # flags
|
||||||
assert tx[12:17] == unhexlify('2400000001') # sequence
|
assert tx[12:17] == unhexlify("2400000001") # sequence
|
||||||
assert tx[17:26] == unhexlify('6140000000000003e8') # amount
|
assert tx[17:26] == unhexlify("6140000000000003e8") # amount
|
||||||
assert tx[26:35] == unhexlify('68400000000000000a') # fee
|
assert tx[26:35] == unhexlify("68400000000000000a") # fee
|
||||||
assert tx[35:70] == unhexlify('7321ed5f5ac8b98974a3ca843326d9b88cebd0560177b973ee0b149f782cfaa06dc66a') # singing pub key
|
assert tx[35:70] == unhexlify(
|
||||||
assert tx[70:92] == unhexlify('81145b812c9d57731e27a2da8b1830195f88ef32a3b6') # account
|
"7321ed5f5ac8b98974a3ca843326d9b88cebd0560177b973ee0b149f782cfaa06dc66a"
|
||||||
assert tx[92:114] == unhexlify('8314b5f762798a53d543a014caf8b297cff8f2f937e8') # destination
|
) # singing pub key
|
||||||
|
assert tx[70:92] == unhexlify(
|
||||||
|
"81145b812c9d57731e27a2da8b1830195f88ef32a3b6"
|
||||||
|
) # account
|
||||||
|
assert tx[92:114] == unhexlify(
|
||||||
|
"8314b5f762798a53d543a014caf8b297cff8f2f937e8"
|
||||||
|
) # destination
|
||||||
assert len(tx[114:]) == 0 # that's it
|
assert len(tx[114:]) == 0 # that's it
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user