stellar: Context is used instead of loop

pull/25/head
Tomas Susanka 6 years ago
parent 8d75fad50c
commit a26aaec953

@ -9,8 +9,8 @@ def dispatch_StellarGetPublicKey(*args, **kwargs):
def dispatch_StellarSignTx(*args, **kwargs):
from .sign_tx import sign_tx_loop
return sign_tx_loop(*args, **kwargs)
from .sign_tx import sign_tx
return sign_tx(*args, **kwargs)
def boot():

@ -2,39 +2,6 @@ from trezor.crypto import base32
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):
"""Returns the base32-encoded version of public key bytes (G...)"""

@ -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.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 consts
from apps.stellar import helpers
@ -11,31 +11,8 @@ from trezor.crypto.curve import ed25519
from trezor.crypto.hashlib import sha256
from ubinascii import hexlify
STELLAR_CURVE = 'ed25519'
TX_TYPE = bytearray('\x00\x00\x00\x02')
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):
async def sign_tx(ctx, msg: StellarSignTx):
if msg.num_operations == 0:
raise ValueError('Stellar: At least one operation is required')
@ -48,16 +25,16 @@ async def sign_tx(ctx, msg):
w = bytearray()
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())
write_pubkey(w, pubkey)
if msg.source_account != pubkey:
raise ValueError('Stellar: source account does not match address_n')
# 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_uint64(w, msg.sequence_number)
@ -91,18 +68,18 @@ async def sign_tx(ctx, msg):
memo_confirm_text = hexlify(msg.memo_hash).decode()
else:
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)
for i in range(msg.num_operations):
op = yield StellarTxOpRequest()
serialize_op(w, op)
op = await ctx.call(StellarTxOpRequest(), *consts.op_wire_types)
await operation(ctx, w, op)
# 4 null bytes representing a (currently unused) empty union
write_uint32(w, 0)
# confirms
await helpers.confirm_final(msg.fee, msg.num_operations)
# final confirm
await layout.require_confirm_final(ctx, msg.fee, msg.num_operations)
# sign
# (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)
# Add the public key for verification that the right account was used for signing
resp = StellarSignedTx()
resp.public_key = pubkey
resp.signature = signature
yield resp
return StellarSignedTx(pubkey, signature)
def node_derive(root, address_n: list):

Loading…
Cancel
Save