1
0
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:
Tomas Susanka 2018-06-05 16:29:12 +02:00
parent 8d75fad50c
commit a26aaec953
4 changed files with 178 additions and 73 deletions

View File

@ -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():

View File

@ -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...)"""

View 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)

View File

@ -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):