Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions common/protob/messages-ton.proto
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,39 @@ message TonSignedProof {
optional bytes signature = 1; // signed transaction message
}


/**
* Request: Require Device to sign TON Connect sign data payload
* @start
* @next TonSignedData
* @next Failure
*/
message TonSignData {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required TonSignDataType type = 2; // payload type
required bytes payload = 3; // payload bytes: TEXT=utf-8 bytes, BINARY=raw bytes, CELL=BOC bytes
optional string schema = 4; // CELL only: schema string included in digest as crc32(utf8(schema))
required string appdomain = 5; // app domain / origin
required uint64 timestamp = 6; // UNIX timestamp in seconds (UTC) at the moment on creating the signature
optional string from_address = 7; // expected signer address for validation only (not part of signed digest)
optional TonWalletVersion wallet_version = 8 [default=V4R2]; // ton wallet version
optional uint32 wallet_id = 9 [default=698983191]; // subwallet_id value
optional TonWorkChain workchain = 10 [default=BASECHAIN];
optional bool is_bounceable = 11 [default=false]; // affects derived/displayed signer address format only
optional bool is_testnet_only = 12 [default=false]; // affects derived/displayed signer address format only

enum TonSignDataType {
TEXT = 0;
BINARY = 1;
CELL = 2;
}
}

/**
* Response: signature corresponding to TonSignData
* @end
*/
message TonSignedData {
optional bytes signature = 1; // ed25519 signature over digest field
optional bytes digest = 2; // exact 32-byte TON Connect signData digest that was signed
}
2 changes: 2 additions & 0 deletions common/protob/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ enum MessageType {
MessageType_TonSignProof = 11905 [(wire_in) = true];
MessageType_TonSignedProof = 11906 [(wire_out) = true];
MessageType_TonTxAck = 11907 [(wire_in) = true];
MessageType_TonSignData = 11908 [(wire_in) = true];
MessageType_TonSignedData = 11909 [(wire_out) = true];

// scdo
MessageType_ScdoGetAddress = 12001 [(wire_in) = true];
Expand Down
2 changes: 1 addition & 1 deletion core/embed/firmware/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#define FIX_VERSION_BUILD VERSION_BUILD

#define ONEKEY_VERSION_MAJOR 4
#define ONEKEY_VERSION_MINOR 20
#define ONEKEY_VERSION_MINOR 21
#define ONEKEY_VERSION_PATCH 0
#define ONEKEY_VERSION_BUILD 0

Expand Down
4 changes: 4 additions & 0 deletions core/src/all_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@
import trezor.enums.SolanaOffChainMessageFormat
trezor.enums.SolanaOffChainMessageVersion
import trezor.enums.SolanaOffChainMessageVersion
trezor.enums.TonSignDataType
import trezor.enums.TonSignDataType
trezor.enums.TonWalletVersion
import trezor.enums.TonWalletVersion
trezor.enums.TonWorkChain
Expand Down Expand Up @@ -891,6 +893,8 @@
import apps.ton.get_address
apps.ton.layout
import apps.ton.layout
apps.ton.sign_data
import apps.ton.sign_data
apps.ton.sign_message
import apps.ton.sign_message
apps.ton.sign_proof
Expand Down
15 changes: 10 additions & 5 deletions core/src/apps/algorand/transactions/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ def as_hash(hash):
"""Confirm that a value is 32 bytes. If all zeros, or a falsy value, return None"""
if not hash:
return None
assert isinstance(hash, (bytes, bytearray)), f"{hash} is not bytes"
if not isinstance(hash, (bytes, bytearray)):
raise TypeError(f"{hash} is not bytes")
if len(hash) != constants.hash_len:
raise error.WrongHashLengthError
if not any(hash):
Expand Down Expand Up @@ -1191,17 +1192,21 @@ def __init__(
@staticmethod
def state_schema(schema):
"""Confirm the argument is a StateSchema, or false which is coerced to None"""
if not schema or not schema.dictify():
if not schema:
return None # Coerce false/empty values to None, to help __eq__
assert isinstance(schema, StateSchema), f"{schema} is not a StateSchema"
if not isinstance(schema, StateSchema):
raise TypeError(f"{schema} is not a StateSchema")
if not schema.dictify():
return None # Coerce empty values to None, to help __eq__
return schema

@staticmethod
def teal_bytes(teal):
"""Confirm the argument is bytes-like, or false which is coerced to None"""
if not teal:
return None # Coerce false values like "" to None, to help __eq__
assert isinstance(teal, (bytes, bytearray)), f"Program {teal} is not bytes"
if not isinstance(teal, (bytes, bytearray)):
raise TypeError(f"Program {teal} is not bytes")
return teal

@staticmethod
Expand All @@ -1216,7 +1221,7 @@ def as_bytes(e):
if isinstance(e, int):
# Uses 8 bytes, big endian to match TEAL's btoi
return e.to_bytes(8, "big") # raises for negative or too big
assert False, f"{e} is not bytes, str, or int"
raise TypeError(f"{e} is not bytes, str, or int")

if not lst:
return None
Expand Down
19 changes: 10 additions & 9 deletions core/src/apps/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,10 @@ async def handle_DoPreauthorized(

req = await ctx.call_any(PreauthorizedRequest(), *wire_types)

assert req.MESSAGE_WIRE_TYPE is not None
handler = workflow_handlers.find_registered_handler(
ctx.iface, req.MESSAGE_WIRE_TYPE
)
wire_type = req.MESSAGE_WIRE_TYPE
if wire_type is None:
return wire.unexpected_message()
handler = workflow_handlers.find_registered_handler(ctx.iface, wire_type)
if handler is None:
return wire.unexpected_message()

Expand Down Expand Up @@ -444,11 +444,12 @@ async def handle_UnlockPath(ctx: wire.Context, msg: UnlockPath) -> protobuf.Mess
wire_types = (MessageType.GetAddress, MessageType.GetPublicKey, MessageType.SignTx)
req = await ctx.call_any(UnlockedPathRequest(mac=expected_mac), *wire_types)

assert req.MESSAGE_WIRE_TYPE in wire_types
handler = workflow_handlers.find_registered_handler(
ctx.iface, req.MESSAGE_WIRE_TYPE
)
assert handler is not None
wire_type = req.MESSAGE_WIRE_TYPE
if wire_type is None or wire_type not in wire_types:
return wire.unexpected_message()
handler = workflow_handlers.find_registered_handler(ctx.iface, wire_type)
if handler is None:
return wire.unexpected_message()
return await handler(ctx, req, msg) # type: ignore [Expected 2 positional arguments]


Expand Down
6 changes: 4 additions & 2 deletions core/src/apps/benfen/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ async def require_show_overview(
if value == "All":
amount_str = "All"
else:
assert isinstance(value, int)
if not isinstance(value, int):
raise TypeError("value must be int")
amount_str = format_benfen_amount(value, currency_symbol)
return await should_show_details(
ctx,
Expand All @@ -42,7 +43,8 @@ async def require_confirm_fee(
if value == "All":
amount_str = "All"
else:
assert isinstance(value, int)
if not isinstance(value, int):
raise TypeError("value must be int")
amount_str = format_benfen_amount(value, currency_symbol)
total_amount = (
format_benfen_amount(value + gas_price, currency_symbol)
Expand Down
3 changes: 2 additions & 1 deletion core/src/apps/binance/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def address_from_public_key(pubkey: bytes, hrp: str) -> str:

h = sha256_ripemd160(pubkey).digest()

assert (len(h) * 8) % 5 == 0 # no padding will be added by convertbits
if (len(h) * 8) % 5 != 0:
raise RuntimeError("Unexpected address hash length")
convertedbits = bech32.convertbits(h, 8, 5)
return bech32.bech32_encode(hrp, convertedbits, bech32.Encoding.BECH32)
9 changes: 6 additions & 3 deletions core/src/apps/bitcoin/addresses.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ def address_p2wsh_in_p2sh(witness_script_hash: bytes, coin: CoinInfo) -> str:


def address_p2wpkh(pubkey: bytes, coin: CoinInfo) -> str:
assert coin.bech32_prefix is not None
if coin.bech32_prefix is None:
raise wire.ProcessError("Bech32 not enabled on this coin")
pubkeyhash = ecdsa_hash_pubkey(pubkey, coin)
return encode_bech32_address(coin.bech32_prefix, 0, pubkeyhash)

Expand All @@ -143,13 +144,15 @@ def address_p2wsh(witness_script_hash: bytes, hrp: str) -> str:


def address_p2tr(pubkey: bytes, coin: CoinInfo) -> str:
assert coin.bech32_prefix is not None
if coin.bech32_prefix is None:
raise wire.ProcessError("Bech32 not enabled on this coin")
output_pubkey = bip340.tweak_public_key(pubkey[1:])
return encode_bech32_address(coin.bech32_prefix, 1, output_pubkey)


def address_to_cashaddr(address: str, coin: CoinInfo) -> str:
assert coin.cashaddr_prefix is not None
if coin.cashaddr_prefix is None:
raise wire.ProcessError("Cashaddr not enabled on this coin")
raw = base58.decode_check(address, coin.b58_hash)
version, data = raw[0], raw[1:]
if version == coin.address_type:
Expand Down
12 changes: 8 additions & 4 deletions core/src/apps/bitcoin/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ def ecdsa_hash_pubkey(pubkey: bytes, coin: CoinInfo) -> bytes:


def encode_bech32_address(prefix: str, witver: int, script: bytes) -> str:
assert witver in _BECH32_WITVERS
if witver not in _BECH32_WITVERS:
raise wire.ProcessError("Invalid address witness version")
address = bech32.encode(prefix, witver, script)
if address is None:
raise wire.ProcessError("Invalid address")
Expand All @@ -137,10 +138,12 @@ def encode_bech32_address(prefix: str, witver: int, script: bytes) -> str:

def decode_bech32_address(prefix: str, address: str) -> tuple[int, bytes]:
witver, raw = bech32.decode(prefix, address)
if witver is None:
raise wire.DataError("Invalid address witness program")
if witver not in _BECH32_WITVERS:
raise wire.DataError("Invalid address witness program")
assert witver is not None
assert raw is not None
if raw is None:
raise wire.DataError("Invalid address witness program")
# check that P2TR address encodes a valid BIP340 public key
if witver == 1 and not bip340.verify_publickey(raw):
raise wire.DataError("Invalid Taproot witness program")
Expand All @@ -162,7 +165,8 @@ def input_is_taproot(txi: TxInput) -> bool:
return True

if txi.script_type == InputScriptType.EXTERNAL:
assert txi.script_pubkey is not None
if txi.script_pubkey is None:
raise wire.DataError("Missing script pubkey")
if txi.script_pubkey[0] == OP_1:
return True

Expand Down
12 changes: 8 additions & 4 deletions core/src/apps/bitcoin/get_public_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,23 @@ async def get_public_key(
and script_type == InputScriptType.SPENDP2SHWITNESS
and (msg.ignore_xpub_magic or coin.xpub_magic_segwit_p2sh is not None)
):
assert coin.xpub_magic_segwit_p2sh is not None
node_xpub = node.serialize_public(
xpub_magic = (
coin.xpub_magic if msg.ignore_xpub_magic else coin.xpub_magic_segwit_p2sh
)
if xpub_magic is None:
raise wire.DataError("Invalid xpub magic")
node_xpub = node.serialize_public(xpub_magic)
elif (
coin.segwit
and script_type == InputScriptType.SPENDWITNESS
and (msg.ignore_xpub_magic or coin.xpub_magic_segwit_native is not None)
):
assert coin.xpub_magic_segwit_native is not None
node_xpub = node.serialize_public(
xpub_magic = (
coin.xpub_magic if msg.ignore_xpub_magic else coin.xpub_magic_segwit_native
)
if xpub_magic is None:
raise wire.DataError("Invalid xpub magic")
node_xpub = node.serialize_public(xpub_magic)
else:
raise wire.DataError("Invalid combination of coin and script_type")

Expand Down
6 changes: 4 additions & 2 deletions core/src/apps/bitcoin/keychain.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,15 @@ def validate_path_against_script_type(
patterns = []

if msg is not None:
assert address_n is None and script_type is None
if address_n is not None or script_type is not None:
raise ValueError("Provide either msg or explicit path/script type")
address_n = msg.address_n
script_type = msg.script_type or InputScriptType.SPENDADDRESS
multisig = bool(getattr(msg, "multisig", False))

else:
assert address_n is not None and script_type is not None
if address_n is None or script_type is None:
raise ValueError("Missing path or script type")

if script_type == InputScriptType.SPENDADDRESS and not multisig:
patterns.append(PATTERN_BIP44)
Expand Down
3 changes: 2 additions & 1 deletion core/src/apps/bitcoin/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def write_input_script_prefixed(
write_bytes_prefixed(w, script_sig)
elif script_type == InputScriptType.SPENDMULTISIG:
# p2sh multisig
assert multisig is not None # checked in sanitize_tx_input
if multisig is None:
raise wire.ProcessError("Missing multisig data")
signature_index = multisig_pubkey_index(multisig, pubkey)
write_input_script_multisig_prefixed(
w, multisig, signature, signature_index, sighash_type, coin
Expand Down
3 changes: 2 additions & 1 deletion core/src/apps/bitcoin/scripts_decred.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def write_input_script_prefixed(
)
elif script_type == InputScriptType.SPENDMULTISIG:
# p2sh multisig
assert multisig is not None # checked in sanitize_tx_input
if multisig is None:
raise wire.ProcessError("Missing multisig data")
signature_index = multisig_pubkey_index(multisig, pubkey)
write_input_script_multisig_prefixed(
w, multisig, signature, signature_index, sighash_type, coin
Expand Down
32 changes: 20 additions & 12 deletions core/src/apps/bitcoin/sign_taproot.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ async def sign_taproot(
found_ours = False
contains_script_path_spending = False
for i, input in enumerate(psbt.inputs):
assert input.prev_txid is not None
assert input.prev_out is not None
assert input.sequence is not None
if input.prev_txid is None:
raise wire.DataError("Missing previous transaction ID")
if input.prev_out is None:
raise wire.DataError("Missing previous output index")
if input.sequence is None:
raise wire.DataError("Missing input sequence")

if input.non_witness_utxo is not None:
# TODO: check if non-witness UTXO is presigned
Expand All @@ -71,7 +74,8 @@ async def sign_taproot(
amount = input.witness_utxo.nValue
is_wit, wit_ver, _ = is_witness(scriptPub)

assert is_wit and wit_ver == 1, "Only taproot input is allowed"
if not is_wit or wit_ver != 1:
raise wire.DataError("Only taproot input is allowed")
total_in += amount
for key, (_, origin) in input.tap_bip32_paths.items():
if origin.fingerprint != master_fp:
Expand All @@ -82,12 +86,15 @@ async def sign_taproot(
raise wire.DataError("Wallet mismatch")
node = keychain.derive(origin.path)
intend_key = node.public_key()[1:]
assert intend_key == key, "Invalid key"
if intend_key != key:
raise wire.DataError("Invalid key")
if not input.tap_scripts:
assert key == input.tap_internal_key, "Invalid internal key"
if key != input.tap_internal_key:
raise wire.DataError("Invalid internal key")
else:
script, _ = list(input.tap_scripts.keys())[0]
assert key in script, "Invalid script"
if key not in script:
raise wire.DataError("Invalid script")
if not contains_script_path_spending:
contains_script_path_spending = True

Expand All @@ -114,7 +121,8 @@ async def sign_taproot(
wit, ver, prog = out.is_witness()
out_address = None
if wit:
assert coin.bech32_prefix is not None
if coin.bech32_prefix is None:
raise wire.DataError("Bech32 not enabled on this coin")
out_address = encode_bech32_address(coin.bech32_prefix, ver, prog)
elif out.is_p2pkh():
out_address = base58.encode_check(
Expand All @@ -128,9 +136,8 @@ async def sign_taproot(
)
elif out.is_opreturn():
if out.nValue != 0:
assert (
contains_script_path_spending and len(psbt.inputs) == 1
), "OpReturn output should have 0 value"
if not (contains_script_path_spending and len(psbt.inputs) == 1):
raise wire.DataError("OpReturn output should have 0 value")
op_return_data = out.scriptPubKey[2:]
else:
raise Exception("Invalid output type")
Expand Down Expand Up @@ -228,7 +235,8 @@ async def sign_taproot(
if not script_path_spending:
input.tap_key_sig = signature
else:
assert leaf_hash is not None
if leaf_hash is None:
raise RuntimeError("Missing leaf hash")
input.tap_script_sigs[(key, leaf_hash)] = signature

return SignedPsbt(psbt=psbt.serialize())
3 changes: 2 additions & 1 deletion core/src/apps/bitcoin/sign_tx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ async def sign_tx(
req = signer.send(res)
if isinstance(req, tuple):
request_class, req = req
assert TxRequest.is_type_of(req)
if not TxRequest.is_type_of(req):
raise RuntimeError("Invalid transaction request")
if req.request_type == RequestType.TXFINISHED:
from trezor.ui.layouts import confirm_final

Expand Down
Loading
Loading