mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-18 11:21:11 +00:00
stellar: Context is used instead of loop
This commit is contained in:
parent
8d75fad50c
commit
a26aaec953
@ -9,8 +9,8 @@ def dispatch_StellarGetPublicKey(*args, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def dispatch_StellarSignTx(*args, **kwargs):
|
def dispatch_StellarSignTx(*args, **kwargs):
|
||||||
from .sign_tx import sign_tx_loop
|
from .sign_tx import sign_tx
|
||||||
return sign_tx_loop(*args, **kwargs)
|
return sign_tx(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def boot():
|
def boot():
|
||||||
|
@ -2,39 +2,6 @@ from trezor.crypto import base32
|
|||||||
import ustruct
|
import ustruct
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmInit:
|
|
||||||
|
|
||||||
def __init__(self, pubkey: bytes, network: str):
|
|
||||||
self.pubkey = pubkey
|
|
||||||
self.network = network
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmMemo:
|
|
||||||
|
|
||||||
def __init__(self, memo_type: int, memo_text: str):
|
|
||||||
self.memo_type = memo_type
|
|
||||||
self.memo_text = memo_text
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmFinal:
|
|
||||||
|
|
||||||
def __init__(self, fee: int, num_operations: int):
|
|
||||||
self.fee = fee
|
|
||||||
self.num_operations = num_operations
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_init(pubkey: bytes, network: str):
|
|
||||||
return (yield UiConfirmInit(pubkey, network))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_memo(memo_type: int, memo_text: str):
|
|
||||||
return (yield UiConfirmMemo(memo_type, memo_text))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_final(fee: int, num_operations: int):
|
|
||||||
return (yield UiConfirmFinal(fee, num_operations))
|
|
||||||
|
|
||||||
|
|
||||||
def address_from_public_key(pubkey: bytes):
|
def address_from_public_key(pubkey: bytes):
|
||||||
"""Returns the base32-encoded version of public key bytes (G...)"""
|
"""Returns the base32-encoded version of public key bytes (G...)"""
|
||||||
|
|
||||||
|
165
src/apps/stellar/operations/serialize.py
Normal file
165
src/apps/stellar/operations/serialize.py
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
from trezor.messages.StellarAccountMergeOp import StellarAccountMergeOp
|
||||||
|
from trezor.messages.StellarAssetType import StellarAssetType
|
||||||
|
from trezor.messages.StellarAllowTrustOp import StellarAllowTrustOp
|
||||||
|
from trezor.messages.StellarBumpSequenceOp import StellarBumpSequenceOp
|
||||||
|
from trezor.messages.StellarChangeTrustOp import StellarChangeTrustOp
|
||||||
|
from trezor.messages.StellarCreateAccountOp import StellarCreateAccountOp
|
||||||
|
from trezor.messages.StellarCreatePassiveOfferOp import StellarCreatePassiveOfferOp
|
||||||
|
from trezor.messages.StellarManageDataOp import StellarManageDataOp
|
||||||
|
from trezor.messages.StellarManageOfferOp import StellarManageOfferOp
|
||||||
|
from trezor.messages.StellarPathPaymentOp import StellarPathPaymentOp
|
||||||
|
from trezor.messages.StellarPaymentOp import StellarPaymentOp
|
||||||
|
from trezor.messages.StellarSetOptionsOp import StellarSetOptionsOp
|
||||||
|
from apps.stellar.consts import *
|
||||||
|
from apps.stellar.writers import *
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_account_merge_op(w, msg: StellarAccountMergeOp):
|
||||||
|
write_pubkey(w, msg.destination_account)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_allow_trust_op(w, msg: StellarAllowTrustOp):
|
||||||
|
# trustor account (the account being allowed to access the asset)
|
||||||
|
write_pubkey(w, msg.trusted_account)
|
||||||
|
write_uint32(w, msg.asset_type)
|
||||||
|
_serialize_asset_code(w, msg.asset_type, msg.asset_code)
|
||||||
|
|
||||||
|
write_bool(w, msg.is_authorized)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_bump_sequence_op(w, msg: StellarBumpSequenceOp):
|
||||||
|
write_uint64(w, msg.bump_to)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_change_trust_op(w, msg: StellarChangeTrustOp):
|
||||||
|
_serialize_asset(w, msg.asset)
|
||||||
|
write_uint64(w, msg.limit)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_create_account_op(w, msg: StellarCreateAccountOp):
|
||||||
|
write_pubkey(w, msg.new_account)
|
||||||
|
write_uint64(w, msg.starting_balance)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_create_passive_offer_op(w, msg: StellarCreatePassiveOfferOp):
|
||||||
|
_serialize_asset(w, msg.selling_asset)
|
||||||
|
_serialize_asset(w, msg.buying_asset)
|
||||||
|
write_uint64(w, msg.amount)
|
||||||
|
write_uint32(w, msg.price_n)
|
||||||
|
write_uint32(w, msg.price_d)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_manage_data_op(w, msg: StellarManageDataOp):
|
||||||
|
if len(msg.key) > 64:
|
||||||
|
raise ValueError('Stellar: max length of a key is 64 bytes')
|
||||||
|
write_string(w, msg.key)
|
||||||
|
write_bool(w, bool(msg.value))
|
||||||
|
if msg.value:
|
||||||
|
write_uint32(w, len(msg.value))
|
||||||
|
write_bytes(w, msg.value)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_manage_offer_op(w, msg: StellarManageOfferOp):
|
||||||
|
_serialize_asset(w, msg.selling_asset)
|
||||||
|
_serialize_asset(w, msg.buying_asset)
|
||||||
|
write_uint64(w, msg.amount) # amount to sell
|
||||||
|
write_uint32(w, msg.price_n) # numerator
|
||||||
|
write_uint32(w, msg.price_d) # denominator
|
||||||
|
write_uint64(w, msg.offer_id)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_path_payment_op(w, msg: StellarPathPaymentOp):
|
||||||
|
_serialize_asset(w, msg.send_asset)
|
||||||
|
write_uint64(w, msg.send_max)
|
||||||
|
write_pubkey(w, msg.destination_account)
|
||||||
|
|
||||||
|
_serialize_asset(w, msg.destination_asset)
|
||||||
|
write_uint64(w, msg.destination_amount)
|
||||||
|
write_uint32(w, len(msg.paths))
|
||||||
|
for p in msg.paths:
|
||||||
|
_serialize_asset(w, p)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_payment_op(w, msg: StellarPaymentOp):
|
||||||
|
write_pubkey(w, msg.destination_account)
|
||||||
|
_serialize_asset(w, msg.asset)
|
||||||
|
write_uint64(w, msg.amount)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_set_options_op(w, msg: StellarSetOptionsOp):
|
||||||
|
# inflation destination
|
||||||
|
write_bool(w, bool(msg.inflation_destination_account))
|
||||||
|
if msg.inflation_destination_account:
|
||||||
|
write_pubkey(w, msg.inflation_destination_account)
|
||||||
|
|
||||||
|
# clear flags
|
||||||
|
write_bool(w, bool(msg.clear_flags))
|
||||||
|
if msg.clear_flags:
|
||||||
|
write_uint32(w, msg.clear_flags)
|
||||||
|
|
||||||
|
# set flags
|
||||||
|
write_bool(w, bool(msg.set_flags))
|
||||||
|
if msg.set_flags:
|
||||||
|
write_uint32(w, msg.set_flags)
|
||||||
|
|
||||||
|
# account thresholds
|
||||||
|
write_bool(w, bool(msg.master_weight))
|
||||||
|
if msg.master_weight:
|
||||||
|
write_uint32(w, msg.master_weight)
|
||||||
|
|
||||||
|
write_bool(w, bool(msg.low_threshold))
|
||||||
|
if msg.low_threshold:
|
||||||
|
write_uint32(w, msg.low_threshold)
|
||||||
|
|
||||||
|
write_bool(w, bool(msg.medium_threshold))
|
||||||
|
if msg.medium_threshold:
|
||||||
|
write_uint32(w, msg.medium_threshold)
|
||||||
|
|
||||||
|
write_bool(w, bool(msg.high_threshold))
|
||||||
|
if msg.high_threshold:
|
||||||
|
write_uint32(w, msg.high_threshold)
|
||||||
|
|
||||||
|
# home domain
|
||||||
|
write_bool(w, bool(msg.home_domain))
|
||||||
|
if msg.home_domain:
|
||||||
|
if len(msg.home_domain) > 32:
|
||||||
|
raise ValueError('Stellar: max length of a home domain is 32 bytes')
|
||||||
|
write_string(w, msg.home_domain)
|
||||||
|
|
||||||
|
# signer
|
||||||
|
write_bool(w, bool(msg.signer_type))
|
||||||
|
if msg.signer_type:
|
||||||
|
# signer type
|
||||||
|
write_uint32(w, msg.signer_type)
|
||||||
|
write_bytes(w, msg.signer_key)
|
||||||
|
write_uint32(w, msg.signer_weight)
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_account(w, source_account: bytes):
|
||||||
|
if source_account is None:
|
||||||
|
write_bool(w, False)
|
||||||
|
return
|
||||||
|
write_pubkey(w, source_account)
|
||||||
|
|
||||||
|
|
||||||
|
def _serialize_asset_code(w, asset_type: int, asset_code: str):
|
||||||
|
code = bytearray(asset_code)
|
||||||
|
if asset_type == ASSET_TYPE_NATIVE:
|
||||||
|
return # nothing is needed
|
||||||
|
elif asset_type == ASSET_TYPE_ALPHANUM4:
|
||||||
|
# pad with zeros to 4 chars
|
||||||
|
write_bytes(w, code + bytearray([0] * (4 - len(code))))
|
||||||
|
elif asset_type == ASSET_TYPE_ALPHANUM12:
|
||||||
|
# pad with zeros to 12 chars
|
||||||
|
write_bytes(w, code + bytearray([0] * (12 - len(code))))
|
||||||
|
else:
|
||||||
|
raise ValueError('Stellar: invalid asset type')
|
||||||
|
|
||||||
|
|
||||||
|
def _serialize_asset(w, asset: StellarAssetType):
|
||||||
|
if asset is None:
|
||||||
|
write_uint32(w, 0)
|
||||||
|
return
|
||||||
|
write_uint32(w, asset.type)
|
||||||
|
_serialize_asset_code(w, asset.type, asset.code)
|
||||||
|
write_pubkey(w, asset.issuer)
|
@ -1,6 +1,6 @@
|
|||||||
from apps.common import seed
|
from apps.common import seed
|
||||||
from apps.stellar.writers import *
|
from apps.stellar.writers import *
|
||||||
from apps.stellar.operations import serialize_op
|
from apps.stellar.operations import operation
|
||||||
from apps.stellar import layout
|
from apps.stellar import layout
|
||||||
from apps.stellar import consts
|
from apps.stellar import consts
|
||||||
from apps.stellar import helpers
|
from apps.stellar import helpers
|
||||||
@ -11,31 +11,8 @@ from trezor.crypto.curve import ed25519
|
|||||||
from trezor.crypto.hashlib import sha256
|
from trezor.crypto.hashlib import sha256
|
||||||
from ubinascii import hexlify
|
from ubinascii import hexlify
|
||||||
|
|
||||||
STELLAR_CURVE = 'ed25519'
|
|
||||||
TX_TYPE = bytearray('\x00\x00\x00\x02')
|
|
||||||
|
|
||||||
|
async def sign_tx(ctx, msg: StellarSignTx):
|
||||||
async def sign_tx_loop(ctx, msg: StellarSignTx):
|
|
||||||
signer = sign_tx(msg, msg)
|
|
||||||
res = None
|
|
||||||
while True:
|
|
||||||
req = signer.send(res)
|
|
||||||
if isinstance(req, StellarTxOpRequest):
|
|
||||||
res = await ctx.call(req, *consts.op_wire_types)
|
|
||||||
elif isinstance(req, StellarSignedTx):
|
|
||||||
break
|
|
||||||
elif isinstance(req, helpers.UiConfirmInit):
|
|
||||||
res = await layout.require_confirm_init(ctx, req.pubkey, req.network)
|
|
||||||
elif isinstance(req, helpers.UiConfirmMemo):
|
|
||||||
res = await layout.require_confirm_memo(ctx, req.memo_type, req.memo_text)
|
|
||||||
elif isinstance(req, helpers.UiConfirmFinal):
|
|
||||||
res = await layout.require_confirm_final(ctx, req.fee, req.num_operations)
|
|
||||||
else:
|
|
||||||
raise TypeError('Stellar: Invalid signing instruction')
|
|
||||||
return req
|
|
||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg):
|
|
||||||
if msg.num_operations == 0:
|
if msg.num_operations == 0:
|
||||||
raise ValueError('Stellar: At least one operation is required')
|
raise ValueError('Stellar: At least one operation is required')
|
||||||
|
|
||||||
@ -48,16 +25,16 @@ async def sign_tx(ctx, msg):
|
|||||||
|
|
||||||
w = bytearray()
|
w = bytearray()
|
||||||
write_bytes(w, network_passphrase_hash)
|
write_bytes(w, network_passphrase_hash)
|
||||||
write_bytes(w, TX_TYPE)
|
write_bytes(w, consts.TX_TYPE)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, STELLAR_CURVE)
|
node = await seed.derive_node(ctx, msg.address_n, consts.STELLAR_CURVE)
|
||||||
pubkey = seed.remove_ed25519_public_key_prefix(node.public_key())
|
pubkey = seed.remove_ed25519_public_key_prefix(node.public_key())
|
||||||
write_pubkey(w, pubkey)
|
write_pubkey(w, pubkey)
|
||||||
if msg.source_account != pubkey:
|
if msg.source_account != pubkey:
|
||||||
raise ValueError('Stellar: source account does not match address_n')
|
raise ValueError('Stellar: source account does not match address_n')
|
||||||
|
|
||||||
# confirm init
|
# confirm init
|
||||||
await helpers.confirm_init(pubkey, msg.network_passphrase)
|
await layout.require_confirm_init(ctx, pubkey, msg.network_passphrase)
|
||||||
|
|
||||||
write_uint32(w, msg.fee)
|
write_uint32(w, msg.fee)
|
||||||
write_uint64(w, msg.sequence_number)
|
write_uint64(w, msg.sequence_number)
|
||||||
@ -91,18 +68,18 @@ async def sign_tx(ctx, msg):
|
|||||||
memo_confirm_text = hexlify(msg.memo_hash).decode()
|
memo_confirm_text = hexlify(msg.memo_hash).decode()
|
||||||
else:
|
else:
|
||||||
raise ValueError('Stellar invalid memo type')
|
raise ValueError('Stellar invalid memo type')
|
||||||
await helpers.confirm_memo(msg.memo_type, memo_confirm_text)
|
await layout.require_confirm_memo(ctx, msg.memo_type, memo_confirm_text)
|
||||||
|
|
||||||
write_uint32(w, msg.num_operations)
|
write_uint32(w, msg.num_operations)
|
||||||
for i in range(msg.num_operations):
|
for i in range(msg.num_operations):
|
||||||
op = yield StellarTxOpRequest()
|
op = await ctx.call(StellarTxOpRequest(), *consts.op_wire_types)
|
||||||
serialize_op(w, op)
|
await operation(ctx, w, op)
|
||||||
|
|
||||||
# 4 null bytes representing a (currently unused) empty union
|
# 4 null bytes representing a (currently unused) empty union
|
||||||
write_uint32(w, 0)
|
write_uint32(w, 0)
|
||||||
|
|
||||||
# confirms
|
# final confirm
|
||||||
await helpers.confirm_final(msg.fee, msg.num_operations)
|
await layout.require_confirm_final(ctx, msg.fee, msg.num_operations)
|
||||||
|
|
||||||
# sign
|
# sign
|
||||||
# (note that the signature does not include the 4-byte hint since it can be calculated from the public key)
|
# (note that the signature does not include the 4-byte hint since it can be calculated from the public key)
|
||||||
@ -110,11 +87,7 @@ async def sign_tx(ctx, msg):
|
|||||||
signature = ed25519.sign(node.private_key(), digest)
|
signature = ed25519.sign(node.private_key(), digest)
|
||||||
|
|
||||||
# Add the public key for verification that the right account was used for signing
|
# Add the public key for verification that the right account was used for signing
|
||||||
resp = StellarSignedTx()
|
return StellarSignedTx(pubkey, signature)
|
||||||
resp.public_key = pubkey
|
|
||||||
resp.signature = signature
|
|
||||||
|
|
||||||
yield resp
|
|
||||||
|
|
||||||
|
|
||||||
def node_derive(root, address_n: list):
|
def node_derive(root, address_n: list):
|
||||||
|
Loading…
Reference in New Issue
Block a user