Merge branch 'release/22.05'

pull/2270/head
Martin Milata 2 years ago
commit c5f1bec474

File diff suppressed because it is too large Load Diff

@ -5,6 +5,9 @@
"erc20:eth:LINK (Chainlink)": {
"name": "Chainlink"
},
"erc20:eth:SOL": {
"shortcut": "SOLA"
},
"eth:CLO": {
"coinmarketcap_alias": "callisto-network"
},

@ -1 +1 @@
Subproject commit c2dcfd82e737d894044635f9cb4f0a6d8cf0d158
Subproject commit 427b0628145b86911ffe571bb1ced0ca883c48f5

@ -1 +1 @@
Subproject commit 502ed91029c4b5c89f5059f561cc98fa346fdda2
Subproject commit 9045282fce6e3b40f6bbed29ce9bf8a86d415cf3

@ -25,7 +25,8 @@
},
"wallet": {
"Account Viewer": "https://accountviewer.stellar.org/",
"Exodus": "https://www.exodus.io"
"Exodus": "https://www.exodus.io",
"Stellarport": "https://stellarport.io/"
}
},
{

File diff suppressed because it is too large Load Diff

@ -82,8 +82,7 @@
},
"bitcoin:RVN": {
"Chaintek": "https://wallet.chaintek.net/",
"Electrum-RVN": "https://github.com/traysi/electrum-raven",
"Mango Farm": "https://mangofarmassets.com/mangowallet"
"Electrum-RVN": "https://github.com/traysi/electrum-raven"
},
"bitcoin:SMART": {
"Electrum-SMART": "https://github.com/smartcash/electrum-smart"

@ -235,7 +235,8 @@ def _load_ethereum_networks():
chain_data = load_json(chain)
shortcut = chain_data["nativeCurrency"]["symbol"]
name = chain_data["name"]
is_testnet = "testnet" in name.lower()
title = chain_data.get("title", "")
is_testnet = "testnet" in name.lower() or "testnet" in title.lower()
if is_testnet:
slip44 = 1
else:

@ -1 +0,0 @@
Ensure input's script type and path match the scriptPubKey.

@ -1 +0,0 @@
Trezor will refuse to sign UTXOs that do not match the provided derivation path (e.g., transactions belonging to a different wallet, or synthetic transaction inputs).

@ -1 +0,0 @@
Support Bitcoin payment requests.

@ -1 +0,0 @@
Automatically choose best size and encoding for QR codes.

@ -1 +0,0 @@
Bitcoin bech32 addresses are encoded in lower-case for QR codes.

@ -1 +0,0 @@
Show "signature is valid" dialog when VerifyMessage succeeds.

@ -1 +0,0 @@
Full type-checking for Python code (except Monero app)

@ -1 +0,0 @@
Support ownership proofs for Taproot addresses.

@ -1 +0,0 @@
EIP-1559 transaction correctly show final Hold to Confirm screen.

@ -1 +0,0 @@
Fix sighash computation in proofs of ownership.

@ -1 +0,0 @@
Fix domain-only EIP-712 hashes (i.e. when `primaryType`=`EIP712Domain`)

@ -1 +0,0 @@
Add extra check for Taproot scripts validity

@ -1 +0,0 @@
Support Electrum signatures in VerifyMessage.

@ -1 +0,0 @@
Support Cardano Alonzo-era transactions (Plutus)

@ -1 +0,0 @@
\[debuglink] Do not wait for screen refresh when _disabling_ layout watching.

@ -1 +0,0 @@
Support unverified external inputs.

@ -1 +0,0 @@
Support Zcash version 5 transaction format

@ -1 +0,0 @@
Support EIP-712 messages where a struct type is only used as an array element.

@ -1 +0,0 @@
GAME, NIX and POLIS support

@ -1 +0,0 @@
Add firmware hashing functionality.

@ -4,6 +4,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 2.5.1 [18th May 2022]
### Added
- Support Bitcoin payment requests. [#1430]
- Show "signature is valid" dialog when VerifyMessage succeeds. [#1880]
- Support ownership proofs for Taproot addresses. [#1944]
- Add extra check for Taproot scripts validity. [#2077]
- Support Electrum signatures in VerifyMessage. [#2100]
- Support Cardano Alonzo-era transactions (Plutus). [#2114]
- Support unverified external inputs. [#2144]
- Support Zcash version 5 transaction format [#2166]
- Add firmware hashing functionality. [#2239]
### Changed
- Ensure input's script type and path match the scriptPubKey. [#1018]
- Automatically choose best size and encoding for QR codes. [#1751]
- Bitcoin bech32 addresses are encoded in lower-case for QR codes. [#1751]
- Full type-checking for Python code (except Monero app). [#1939]
- \[debuglink] Do not wait for screen refresh when _disabling_ layout watching. [#2135]
### Removed
- GAME, NIX and POLIS support. [#2181]
### Fixed
- EIP-1559 transaction correctly show final Hold to Confirm screen. [#2020]
- Fix sighash computation in proofs of ownership. [#2034]
- Fix domain-only EIP-712 hashes (i.e. when `primaryType`=`EIP712Domain`). [#2036]
- Support EIP-712 messages where a struct type is only used as an array element. [#2167]
### Security
- Fix a coin loss vulnerability related to replacement transactions with multisig inputs and unverified external inputs.
### Incompatible changes
- Trezor will refuse to sign UTXOs that do not match the provided derivation path (e.g., transactions belonging to a different wallet, or synthetic transaction inputs). [#1018]
## 2.4.3 [8th December 2021]
### Added
@ -451,6 +488,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#948]: https://github.com/trezor/trezor-firmware/pull/948
[#958]: https://github.com/trezor/trezor-firmware/pull/958
[#982]: https://github.com/trezor/trezor-firmware/pull/982
[#1018]: https://github.com/trezor/trezor-firmware/pull/1018
[#1027]: https://github.com/trezor/trezor-firmware/pull/1027
[#1030]: https://github.com/trezor/trezor-firmware/pull/1030
[#1042]: https://github.com/trezor/trezor-firmware/pull/1042
@ -494,6 +532,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1402]: https://github.com/trezor/trezor-firmware/pull/1402
[#1404]: https://github.com/trezor/trezor-firmware/pull/1404
[#1415]: https://github.com/trezor/trezor-firmware/pull/1415
[#1430]: https://github.com/trezor/trezor-firmware/pull/1430
[#1431]: https://github.com/trezor/trezor-firmware/pull/1431
[#1456]: https://github.com/trezor/trezor-firmware/pull/1456
[#1467]: https://github.com/trezor/trezor-firmware/pull/1467
@ -531,6 +570,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1708]: https://github.com/trezor/trezor-firmware/pull/1708
[#1710]: https://github.com/trezor/trezor-firmware/pull/1710
[#1744]: https://github.com/trezor/trezor-firmware/pull/1744
[#1751]: https://github.com/trezor/trezor-firmware/pull/1751
[#1755]: https://github.com/trezor/trezor-firmware/pull/1755
[#1765]: https://github.com/trezor/trezor-firmware/pull/1765
[#1767]: https://github.com/trezor/trezor-firmware/pull/1767
@ -545,3 +585,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1838]: https://github.com/trezor/trezor-firmware/pull/1838
[#1857]: https://github.com/trezor/trezor-firmware/pull/1857
[#1872]: https://github.com/trezor/trezor-firmware/pull/1872
[#1880]: https://github.com/trezor/trezor-firmware/pull/1880
[#1939]: https://github.com/trezor/trezor-firmware/pull/1939
[#1944]: https://github.com/trezor/trezor-firmware/pull/1944
[#2020]: https://github.com/trezor/trezor-firmware/pull/2020
[#2034]: https://github.com/trezor/trezor-firmware/pull/2034
[#2036]: https://github.com/trezor/trezor-firmware/pull/2036
[#2077]: https://github.com/trezor/trezor-firmware/pull/2077
[#2100]: https://github.com/trezor/trezor-firmware/pull/2100
[#2114]: https://github.com/trezor/trezor-firmware/pull/2114
[#2135]: https://github.com/trezor/trezor-firmware/pull/2135
[#2144]: https://github.com/trezor/trezor-firmware/pull/2144
[#2166]: https://github.com/trezor/trezor-firmware/pull/2166
[#2167]: https://github.com/trezor/trezor-firmware/pull/2167
[#2181]: https://github.com/trezor/trezor-firmware/pull/2181
[#2239]: https://github.com/trezor/trezor-firmware/pull/2239

@ -50,6 +50,7 @@ class Approver:
self.orig_change_out = 0 # sum of original change output amounts
self.amount_unit = tx.amount_unit
self.has_unverified_external_input = False
def is_payjoin(self) -> bool:
# A PayJoin is a replacement transaction which manipulates the external inputs of the
@ -73,6 +74,7 @@ class Approver:
self.orig_total_in += txi.amount
if input_is_external_unverified(txi):
self.has_unverified_external_input = True
if safety_checks.is_strict():
raise wire.ProcessError("Unverifiable external input.")
else:
@ -235,6 +237,9 @@ class BasicApprover(Approver):
async def approve_tx(self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo]) -> None:
await super().approve_tx(tx_info, orig_txs)
if self.has_unverified_external_input:
await helpers.confirm_unverified_external_input()
fee = self.total_in - self.total_out
# some coins require negative fees for reward TX

@ -122,9 +122,9 @@ class Bitcoin:
# stable device tests.
self.orig_txs: list[OriginalTxInfo] = []
# The digests of the inputs streamed for approval in Step 1. These are used to ensure that
# the inputs streamed for verification in Step 3 are the same as those in Step 1.
self.h_inputs: bytes | None = None
# The digests of the external inputs streamed for approval in Step 1. These are used
# to ensure that the inputs streamed for verification in Step 3 are the same as
# those in Step 1.
self.h_external_inputs: bytes | None = None
# The index of the payment request being processed.
@ -165,11 +165,12 @@ class Bitcoin:
if txi.orig_hash:
await self.process_original_input(txi, script_pubkey)
self.h_inputs = self.tx_info.get_tx_check_digest()
self.tx_info.h_inputs_check = self.tx_info.get_tx_check_digest()
self.h_external_inputs = h_external_inputs_check.get_digest()
# Finalize original inputs.
for orig in self.orig_txs:
orig.h_inputs_check = orig.get_tx_check_digest()
if orig.index != orig.tx.inputs_count:
raise wire.ProcessError("Removal of original inputs is not supported.")
@ -194,7 +195,7 @@ class Bitcoin:
await orig.finalize_tx_hash()
async def step3_verify_inputs(self) -> None:
# should come out the same as h_inputs, checked before continuing
# should come out the same as h_inputs_check, checked before continuing
h_check = HashWriter(sha256())
if self.taproot_only:
@ -220,7 +221,7 @@ class Bitcoin:
# inputs or to falsely claim that a transaction is a replacement of an already approved
# transaction or to construct a valid transaction by combining signatures obtained in
# multiple rounds of the attack.
expected_digest = self.h_inputs
expected_digest = self.tx_info.h_inputs_check
for i in range(self.tx_info.tx.inputs_count):
progress.advance()
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
@ -406,29 +407,34 @@ class Bitcoin:
async def verify_original_txs(self) -> None:
for orig in self.orig_txs:
if orig.verification_input is None:
raise wire.ProcessError(
"Each original transaction must specify address_n for at least one input."
# should come out the same as h_inputs_check, checked before continuing
h_check = HashWriter(sha256())
for i in range(orig.tx.inputs_count):
txi = await helpers.request_tx_input(
self.tx_req, i, self.coin, orig.orig_hash
)
writers.write_tx_input_check(h_check, txi)
script_pubkey = self.input_derive_script(txi)
verifier = SignatureVerifier(
script_pubkey, txi.script_sig, txi.witness, self.coin
)
verifier.ensure_hash_type(
(SigHashType.SIGHASH_ALL_TAPROOT, self.get_sighash_type(txi))
)
tx_digest = await self.get_tx_digest(
i,
txi,
orig,
verifier.public_keys,
verifier.threshold,
script_pubkey,
)
verifier.verify(tx_digest)
assert orig.verification_index is not None
txi = orig.verification_input
script_pubkey = self.input_derive_script(txi)
verifier = SignatureVerifier(
script_pubkey, txi.script_sig, txi.witness, self.coin
)
verifier.ensure_hash_type(
(SigHashType.SIGHASH_ALL_TAPROOT, self.get_sighash_type(txi))
)
tx_digest = await self.get_tx_digest(
orig.verification_index,
txi,
orig,
verifier.public_keys,
verifier.threshold,
script_pubkey,
)
verifier.verify(tx_digest)
# check that the inputs were the same as those streamed for approval
if h_check.get_digest() != orig.h_inputs_check:
raise wire.ProcessError("Transaction has changed during signing")
async def approve_output(
self,

@ -180,6 +180,11 @@ class UiConfirmChangeCountOverThreshold(UiConfirm):
return layout.confirm_change_count_over_threshold(ctx, self.change_count)
class UiConfirmUnverifiedExternalInput(UiConfirm):
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_unverified_external_input(ctx)
class UiConfirmForeignAddress(UiConfirm):
def __init__(self, address_n: list):
self.address_n = address_n
@ -239,6 +244,10 @@ def confirm_change_count_over_threshold(change_count: int) -> Awaitable[Any]: #
return (yield UiConfirmChangeCountOverThreshold(change_count))
def confirm_unverified_external_input() -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmUnverifiedExternalInput())
def confirm_foreign_address(address_n: list) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmForeignAddress(address_n))

@ -220,6 +220,16 @@ async def confirm_change_count_over_threshold(
)
async def confirm_unverified_external_input(ctx: wire.Context) -> None:
await layouts.confirm_metadata(
ctx,
"unverified_external_input",
"Warning",
"The transaction contains unverified external inputs.",
br_code=ButtonRequestType.SignTx,
)
async def confirm_nondefault_locktime(
ctx: wire.Context, lock_time: int, lock_time_disabled: bool
) -> None:

@ -72,6 +72,11 @@ class TxInfoBase:
# in Steps 1 and 2 and the ones streamed for signing legacy inputs in Step 4.
self.h_tx_check = HashWriter(sha256()) # not a real tx hash
# The digests of the inputs streamed for approval in Step 1. These are used to
# ensure that the inputs streamed for verification in Step 3 are the same as
# those in Step 1.
self.h_inputs_check: bytes | None = None
# BIP-0143 transaction hashing.
self.sig_hasher = signer.create_sig_hasher(tx)
@ -145,19 +150,10 @@ class OriginalTxInfo(TxInfoBase):
signer.write_tx_header(self.h_tx, tx, witness_marker=False)
writers.write_compact_size(self.h_tx, tx.inputs_count)
# The input which will be used for verification and its index in the original transaction.
self.verification_input: TxInput | None = None
self.verification_index: int | None = None
def add_input(self, txi: TxInput, script_pubkey: bytes) -> None:
super().add_input(txi, script_pubkey)
writers.write_tx_input(self.h_tx, txi, txi.script_sig or bytes())
# For verification use the first original input that specifies address_n.
if not self.verification_input and txi.address_n:
self.verification_input = txi
self.verification_index = self.index
def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
super().add_output(txo, script_pubkey)

@ -15,8 +15,6 @@ from apps.common.writers import ( # noqa: F401
write_uint64_le,
)
from .common import input_is_external_unverified
if TYPE_CHECKING:
from trezor.messages import (
PrevInput,
@ -48,15 +46,23 @@ def write_tx_input(w: Writer, i: TxInput | PrevInput, script: bytes) -> None:
def write_tx_input_check(w: Writer, i: TxInput) -> None:
write_bytes_fixed(w, i.prev_hash, TX_HASH_SIZE)
write_uint32(w, i.prev_index)
write_uint32(w, i.script_type)
write_uint8(w, input_is_external_unverified(i))
from .multisig import multisig_fingerprint
write_uint32(w, len(i.address_n))
for n in i.address_n:
write_uint32(w, n)
write_bytes_fixed(w, i.prev_hash, TX_HASH_SIZE)
write_uint32(w, i.prev_index)
write_bytes_prefixed(w, i.script_sig or b"")
write_uint32(w, i.sequence)
write_uint32(w, i.script_type)
multisig_fp = multisig_fingerprint(i.multisig) if i.multisig else b""
write_bytes_prefixed(w, multisig_fp)
write_uint64(w, i.amount or 0)
write_bytes_prefixed(w, i.witness or b"")
write_bytes_prefixed(w, i.ownership_proof or b"")
write_bytes_prefixed(w, i.orig_hash or b"")
write_uint32(w, i.orig_index or 0)
write_bytes_prefixed(w, i.script_pubkey or b"")

@ -60,21 +60,21 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
chain_id=3,
slip44=1,
shortcut="tROP",
name="Ethereum Testnet Ropsten",
name="Ropsten",
rskip60=False,
)
yield NetworkInfo(
chain_id=4,
slip44=1,
shortcut="tRIN",
name="Ethereum Testnet Rinkeby",
name="Rinkeby",
rskip60=False,
)
yield NetworkInfo(
chain_id=5,
slip44=1,
shortcut="tGOR",
name="Ethereum Testnet Görli",
name="Görli",
rskip60=False,
)
yield NetworkInfo(
@ -105,13 +105,6 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Ubiq Network Testnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=10,
slip44=60,
shortcut="OETH",
name="Optimistic Ethereum",
rskip60=False,
)
yield NetworkInfo(
chain_id=11,
slip44=916,
@ -179,7 +172,14 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
chain_id=20,
slip44=60,
shortcut="ELA",
name="ELA-ETH-Sidechain",
name="Elastos Smart Chain",
rskip60=False,
)
yield NetworkInfo(
chain_id=24,
slip44=60,
shortcut="DTH",
name="Dithereum",
rskip60=False,
)
yield NetworkInfo(
@ -249,7 +249,7 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
chain_id=42,
slip44=1,
shortcut="tKOV",
name="Ethereum Testnet Kovan",
name="Kovan",
rskip60=False,
)
yield NetworkInfo(
@ -340,7 +340,7 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
chain_id=66,
slip44=60,
shortcut="OKT",
name="OKExChain",
name="OKXChain",
rskip60=False,
)
yield NetworkInfo(
@ -361,7 +361,14 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
chain_id=69,
slip44=1,
shortcut="tKOR",
name="Optimistic Ethereum Testnet Kovan",
name="Optimism Kovan",
rskip60=False,
)
yield NetworkInfo(
chain_id=74,
slip44=60,
shortcut="EIDI",
name="IDChain",
rskip60=False,
)
yield NetworkInfo(
@ -406,6 +413,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="GateChain",
rskip60=False,
)
yield NetworkInfo(
chain_id=87,
slip44=60,
shortcut="SNT",
name="Nova Network",
rskip60=False,
)
yield NetworkInfo(
chain_id=88,
slip44=889,
@ -413,6 +427,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="TomoChain",
rskip60=False,
)
yield NetworkInfo(
chain_id=90,
slip44=60,
shortcut="GAR",
name="Garizon Stage0",
rskip60=False,
)
yield NetworkInfo(
chain_id=96,
slip44=60,
@ -448,6 +469,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="EtherInc",
rskip60=False,
)
yield NetworkInfo(
chain_id=105,
slip44=60,
shortcut="W3G",
name="Web3Games Devnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=106,
slip44=60,
@ -490,6 +518,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Decentralized Web",
rskip60=False,
)
yield NetworkInfo(
chain_id=126,
slip44=126,
shortcut="OY",
name="OYchain",
rskip60=False,
)
yield NetworkInfo(
chain_id=127,
slip44=127,
@ -567,6 +602,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Permission",
rskip60=False,
)
yield NetworkInfo(
chain_id=225,
slip44=60,
shortcut="LA",
name="LACHAIN",
rskip60=False,
)
yield NetworkInfo(
chain_id=246,
slip44=246,
@ -588,6 +630,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Huobi ECO Chain Testnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=258,
slip44=60,
shortcut="SETM",
name="Setheum",
rskip60=False,
)
yield NetworkInfo(
chain_id=262,
slip44=60,
@ -609,6 +658,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="KCC",
rskip60=False,
)
yield NetworkInfo(
chain_id=333,
slip44=60,
shortcut="W3Q",
name="Web3Q",
rskip60=False,
)
yield NetworkInfo(
chain_id=336,
slip44=60,
@ -644,6 +700,20 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Rupaya",
rskip60=False,
)
yield NetworkInfo(
chain_id=512,
slip44=1512,
shortcut="AAC",
name="Double-A Chain",
rskip60=False,
)
yield NetworkInfo(
chain_id=555,
slip44=60,
shortcut="CLASS",
name="Vela1 Chain",
rskip60=False,
)
yield NetworkInfo(
chain_id=558,
slip44=60,
@ -665,6 +735,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Karura Network",
rskip60=False,
)
yield NetworkInfo(
chain_id=707,
slip44=60,
shortcut="BCS",
name="BlockChain Station",
rskip60=False,
)
yield NetworkInfo(
chain_id=777,
slip44=60,
@ -770,6 +847,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Clover",
rskip60=False,
)
yield NetworkInfo(
chain_id=1030,
slip44=60,
shortcut="CFX",
name="Conflux eSpace",
rskip60=False,
)
yield NetworkInfo(
chain_id=1088,
slip44=60,
@ -791,6 +875,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="MathChain Testnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=1197,
slip44=60,
shortcut="IORA",
name="Iora Chain",
rskip60=False,
)
yield NetworkInfo(
chain_id=1202,
slip44=60,
@ -805,6 +896,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Popcateum",
rskip60=False,
)
yield NetworkInfo(
chain_id=1214,
slip44=60,
shortcut="ENTER",
name="EnterChain",
rskip60=False,
)
yield NetworkInfo(
chain_id=1280,
slip44=60,
@ -826,13 +924,6 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Moonriver",
rskip60=False,
)
yield NetworkInfo(
chain_id=1286,
slip44=60,
shortcut="ROC",
name="Moonrock",
rskip60=False,
)
yield NetworkInfo(
chain_id=1287,
slip44=60,
@ -843,8 +934,8 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
yield NetworkInfo(
chain_id=1288,
slip44=60,
shortcut="MSHD",
name="Moonshadow",
shortcut="ROC",
name="Moonrock",
rskip60=False,
)
yield NetworkInfo(
@ -868,6 +959,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Teslafunds",
rskip60=False,
)
yield NetworkInfo(
chain_id=1898,
slip44=60,
shortcut="BOY",
name="BON Network",
rskip60=False,
)
yield NetworkInfo(
chain_id=1987,
slip44=1987,
@ -903,6 +1001,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Ecoball",
rskip60=False,
)
yield NetworkInfo(
chain_id=2213,
slip44=60,
shortcut="EVA",
name="Evanesco",
rskip60=False,
)
yield NetworkInfo(
chain_id=2559,
slip44=60,
@ -910,6 +1015,20 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Kortho",
rskip60=False,
)
yield NetworkInfo(
chain_id=3400,
slip44=60,
shortcut="PRB",
name="Paribu Net",
rskip60=False,
)
yield NetworkInfo(
chain_id=3966,
slip44=60,
shortcut="DYNO",
name="DYNO",
rskip60=False,
)
yield NetworkInfo(
chain_id=4689,
slip44=60,
@ -945,6 +1064,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Pixie Chain",
rskip60=False,
)
yield NetworkInfo(
chain_id=8000,
slip44=60,
shortcut="TELE",
name="Teleport",
rskip60=False,
)
yield NetworkInfo(
chain_id=8217,
slip44=8217,
@ -966,6 +1092,20 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="bloxberg",
rskip60=False,
)
yield NetworkInfo(
chain_id=9001,
slip44=60,
shortcut="EVMOS",
name="Evmos",
rskip60=False,
)
yield NetworkInfo(
chain_id=9100,
slip44=60,
shortcut="GNC",
name="Genesis Coin",
rskip60=False,
)
yield NetworkInfo(
chain_id=10101,
slip44=60,
@ -973,6 +1113,20 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Blockchain Genesis",
rskip60=False,
)
yield NetworkInfo(
chain_id=10823,
slip44=60,
shortcut="CCP",
name="CryptoCoinPay",
rskip60=False,
)
yield NetworkInfo(
chain_id=11111,
slip44=60,
shortcut="WGM",
name="WAGMI",
rskip60=False,
)
yield NetworkInfo(
chain_id=12052,
slip44=621,
@ -980,6 +1134,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Singularity ZERO",
rskip60=False,
)
yield NetworkInfo(
chain_id=13381,
slip44=60,
shortcut="PHX",
name="Phoenix",
rskip60=False,
)
yield NetworkInfo(
chain_id=16000,
slip44=60,
@ -994,6 +1155,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="BTCIX Network",
rskip60=False,
)
yield NetworkInfo(
chain_id=21816,
slip44=60,
shortcut="OML",
name="omChain",
rskip60=False,
)
yield NetworkInfo(
chain_id=24484,
slip44=227,
@ -1059,9 +1227,9 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
)
yield NetworkInfo(
chain_id=43114,
slip44=9000,
slip44=9005,
shortcut="AVAX",
name="Avalanche",
name="Avalanche C-Chain",
rskip60=False,
)
yield NetworkInfo(
@ -1071,6 +1239,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Celo Alfajores Testnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=47805,
slip44=60,
shortcut="REI",
name="REI Network",
rskip60=False,
)
yield NetworkInfo(
chain_id=49797,
slip44=1,
@ -1078,6 +1253,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Energi Testnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=53935,
slip44=60,
shortcut="JEWEL",
name="DFK Chain",
rskip60=False,
)
yield NetworkInfo(
chain_id=62320,
slip44=1,
@ -1085,6 +1267,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Celo Baklava Testnet",
rskip60=False,
)
yield NetworkInfo(
chain_id=63000,
slip44=60,
shortcut="ECS",
name="eCredits",
rskip60=False,
)
yield NetworkInfo(
chain_id=73799,
slip44=1,
@ -1103,7 +1292,14 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
chain_id=80001,
slip44=1,
shortcut="tMATIC",
name="Polygon Testnet Mumbai",
name="Mumbai",
rskip60=False,
)
yield NetworkInfo(
chain_id=99999,
slip44=60,
shortcut="UBC",
name="UB Smart Chain",
rskip60=False,
)
yield NetworkInfo(
@ -1169,6 +1365,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="QuarkChain",
rskip60=False,
)
yield NetworkInfo(
chain_id=108801,
slip44=60,
shortcut="BRO",
name="BROChain",
rskip60=False,
)
yield NetworkInfo(
chain_id=200625,
slip44=200625,
@ -1183,6 +1386,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Alaya",
rskip60=False,
)
yield NetworkInfo(
chain_id=210425,
slip44=60,
shortcut="lat",
name="PlatON",
rskip60=False,
)
yield NetworkInfo(
chain_id=246529,
slip44=246529,
@ -1211,6 +1421,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Polis",
rskip60=False,
)
yield NetworkInfo(
chain_id=888888,
slip44=60,
shortcut="VS",
name="Vision -",
rskip60=False,
)
yield NetworkInfo(
chain_id=955305,
slip44=1011,
@ -1239,6 +1456,13 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="Musicoin",
rskip60=False,
)
yield NetworkInfo(
chain_id=11155111,
slip44=1,
shortcut="tSEP",
name="Sepolia",
rskip60=False,
)
yield NetworkInfo(
chain_id=13371337,
slip44=60,
@ -1309,13 +1533,6 @@ def _networks_iterator() -> Iterator[NetworkInfo]:
name="IPOS Network",
rskip60=False,
)
yield NetworkInfo(
chain_id=1313161554,
slip44=60,
shortcut="aETH",
name="Aurora",
rskip60=False,
)
yield NetworkInfo(
chain_id=1666600000,
slip44=60,

@ -85,6 +85,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("AFA", 2) # eth / Africahead Ipparts
if address == b"\x8e\xb2\x43\x19\x39\x37\x16\x66\x8d\x76\x8d\xce\xc2\x93\x56\xae\x9c\xff\xe2\x85":
return TokenInfo("AGI", 8) # eth / SingularityNET
if address == b"\x73\x88\x65\x30\x1a\x9b\x7d\xd8\x0d\xc3\x66\x6d\xd4\x8c\xf0\x34\xec\x42\xbd\xda":
return TokenInfo("AGRS", 8) # eth / Agoras: Currency of Tau
if address == b"\x7d\xb5\x45\x4f\x35\x00\xf2\x81\x71\xd1\xf9\xc7\xa3\x85\x27\xc9\xcf\x94\xe6\xb2":
return TokenInfo("AGS", 4) # eth / Silver Standard
if address == b"\x51\x21\xe3\x48\xe8\x97\xda\xef\x1e\xef\x23\x95\x9a\xb2\x90\xe5\x55\x7c\xf2\x74":
@ -113,6 +115,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("aLINK", 18) # eth / Aave Interest bearing LINK
if address == b"\xea\x61\x0b\x11\x53\x47\x77\x20\x74\x8d\xc1\x3e\xd3\x78\x00\x39\x41\xd8\x4f\xab":
return TokenInfo("ALIS", 18) # eth / ALIS Token
if address == b"\xe0\xcc\xa8\x6b\x25\x40\x05\x88\x9a\xc3\xa8\x1e\x73\x7f\x56\xa1\x4f\x4a\x38\xf5":
return TokenInfo("ALTA", 18) # eth / Alta Finance
if address == b"\x63\x8a\xc1\x49\xea\x8e\xf9\xa1\x28\x6c\x41\xb9\x77\x01\x7a\xa7\x35\x9e\x6c\xfa":
return TokenInfo("ALTS", 18) # eth / ALTS Token
if address == b"\x49\xb1\x27\xbc\x33\xce\x7e\x15\x86\xec\x28\xce\xc6\xa6\x5b\x11\x25\x96\xc8\x22":
@ -521,8 +525,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("CHSB", 8) # eth / SwissBorg
if address == b"\x14\x60\xa5\x80\x96\xd8\x0a\x50\xa2\xf1\xf9\x56\xdd\xa4\x97\x61\x1f\xa4\xf1\x65":
return TokenInfo("CHX", 18) # eth / Own
if address == b"\x00\x38\x01\x43\x12\x91\x67\x39\x5e\x8b\x4f\x0a\x35\xed\xc1\xbc\x60\xe7\xce\x65":
return TokenInfo("CIG", 8) # eth / Clorigin
if address == b"\x37\xfe\x0f\x06\x7f\xa8\x08\xff\xbd\xd1\x28\x91\xc0\x85\x85\x32\xcf\xe7\x36\x1d":
return TokenInfo("CIV", 18) # eth / Civilization
if address == b"\xf7\x5f\xbf\xa2\xf6\x81\x86\x0b\x9a\x6d\x19\xfc\x3f\xf3\xd3\x4c\xb3\x22\xe2\xd6":
@ -555,6 +557,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("CNB", 8) # eth / Canabio
if address == b"\xd4\xc4\x35\xf5\xb0\x9f\x85\x5c\x33\x17\xc8\x52\x4c\xb1\xf5\x86\xe4\x27\x95\xfa":
return TokenInfo("CND", 18) # eth / Cindicator
if address == b"\xbc\x13\x8b\xd2\x0c\x98\x18\x6c\xc0\x34\x2c\x8e\x38\x09\x53\xaf\x0c\xb4\x8b\xa8":
return TokenInfo("CNDL", 18) # eth / Candle
if address == b"\x87\x13\xd2\x66\x37\xcf\x49\xe1\xb6\xb4\xa7\xce\x57\x10\x6a\xab\xc9\x32\x53\x43":
return TokenInfo("CNN", 18) # eth / Content Neutrality Network
if address == b"\xb4\xb1\xd2\xc2\x17\xec\x07\x76\x58\x4c\xe0\x8d\x3d\xd9\x8f\x90\xed\xed\xa4\x4b":
@ -677,8 +681,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("DACS", 18) # eth / DACSEE
if address == b"\xfb\x2f\x26\xf2\x66\xfb\x28\x05\xa3\x87\x23\x0f\x2a\xa0\xa3\x31\xb4\xd9\x6f\xba":
return TokenInfo("DADI", 18) # eth / DADI
if address == b"\x6b\x17\x54\x74\xe8\x90\x94\xc4\x4d\xa9\x8b\x95\x4e\xed\xea\xc4\x95\x27\x1d\x0f":
return TokenInfo("DAI", 18) # eth / Dai Stablecoin v2.0
if address == b"\x1d\x01\x98\x82\x9c\xba\x76\x8e\x4e\xf2\xf7\x62\xcd\x82\x84\x2b\xba\x3e\x34\x58":
return TokenInfo("DAF", 6) # eth / Diamonds are Forever
if address == b"\x07\xd9\xe4\x9e\xa4\x02\x19\x4b\xf4\x8a\x82\x76\xda\xfb\x16\xe4\xed\x63\x33\x17":
return TokenInfo("DALC", 8) # eth / DaleCoin
if address == b"\x9b\x70\x74\x0e\x70\x8a\x08\x3c\x6f\xf3\x8d\xf5\x22\x97\x02\x0f\x5d\xfa\xa5\xee":
@ -731,8 +735,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("DEX", 18) # eth / DEX
if address == b"\x43\x1a\xd2\xff\x6a\x9c\x36\x58\x05\xeb\xad\x47\xee\x02\x11\x48\xd6\xf7\xdb\xe0":
return TokenInfo("DF", 18) # eth / dForce Platform Token
if address == b"\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a":
return TokenInfo("DGD", 9) # eth / Digix DAO
if address == b"\xf6\xcf\xe5\x3d\x6f\xeb\xae\xea\x05\x1f\x40\x0f\xf5\xfc\x14\xf0\xcb\xbd\xac\xa1":
return TokenInfo("DGPT", 18) # eth / DigiPulse
if address == b"\x6a\xed\xbf\x8d\xff\x31\x43\x72\x20\xdf\x35\x19\x50\xba\x2a\x33\x62\x16\x8d\x1b":
@ -1213,8 +1215,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("GLA", 8) # eth / Gladius
if address == b"\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96":
return TokenInfo("GNO", 18) # eth / Gnosis
if address == b"\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d":
return TokenInfo("GNT", 18) # eth / Golem
if address == b"\x6e\xc8\xa2\x4c\xab\xdc\x33\x9a\x06\xa1\x72\xf8\x22\x3e\xa5\x57\x05\x5a\xda\xa5":
return TokenInfo("GNX", 9) # eth / Genaro Network
if address == b"\x24\x75\x51\xf2\xeb\x33\x62\xe2\x22\xc7\x42\xe9\xc7\x88\xb8\x95\x7d\x9b\xc8\x7e":
@ -1255,8 +1255,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("GUESS", 2) # eth / Peerguess
if address == b"\x98\x47\x34\x5d\xe8\xb6\x14\xc9\x56\x14\x6b\xbe\xa5\x49\x33\x6d\x9c\x8d\x26\xb6":
return TokenInfo("GULD", 8) # eth / GULD ERC20
if address == b"\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c":
return TokenInfo("GUP", 3) # eth / Matchpool
if address == b"\x05\x6f\xd4\x09\xe1\xd7\xa1\x24\xbd\x70\x17\x45\x9d\xfe\xa2\xf3\x87\xb6\xd5\xcd":
return TokenInfo("GUSD", 2) # eth / Gemini dollar
if address == b"\x10\x3c\x3a\x20\x9d\xa5\x9d\x3e\x7c\x4a\x89\x30\x7e\x66\x52\x1e\x08\x1c\xfd\xf0":
@ -1503,8 +1501,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("KAN", 18) # eth / BitKan
if address == b"\xe1\x52\x54\xa1\x3d\x34\xf9\x70\x03\x20\x33\x0a\xbc\xb7\xc7\xf8\x57\xaf\x2f\xb7":
return TokenInfo("KAPA", 2) # eth / KAPA COIN
if address == b"\x0d\x6d\xd9\xf6\x8d\x24\xec\x1d\x5f\xe2\x17\x4f\x3e\xc8\xda\xb5\x2b\x52\xba\xf5":
return TokenInfo("KC", 18) # eth / KMCC
if address == b"\x03\x9b\x56\x49\xa5\x99\x67\xe3\xe9\x36\xd7\x47\x1f\x9c\x37\x00\x10\x0e\xe1\xab":
return TokenInfo("KCS", 6) # eth / KuCoin
if address == b"\x72\xd3\x2a\xc1\xc5\xe6\x6b\xfc\x5b\x08\x80\x62\x71\xf8\xee\xf9\x15\x54\x51\x64":
@ -1625,6 +1621,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("[deprecated] LRC (old)", 18) # eth / Loopring
if address == b"\x5d\xbe\x29\x6f\x97\xb2\x3c\x4a\x6a\xa6\x18\x3d\x73\xe5\x74\xd0\x2b\xa5\xc7\x19":
return TokenInfo("LUC", 18) # eth / LUCToken
if address == b"\xa5\xef\x74\x06\x8d\x04\xba\x08\x09\xb7\x37\x9d\xd7\x6a\xf5\xce\x34\xab\x7c\x57":
return TokenInfo("LUCHOW", 18) # eth / LunaChow
if address == b"\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53":
return TokenInfo("LUCK", 0) # eth / LUCK
if address == b"\x01\xcd\x3d\x9d\xf5\x86\x9c\xa7\x95\x47\x45\x66\x3b\xd6\x20\x1c\x57\x1e\x05\xcf":
@ -1667,6 +1665,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("MDT", 18) # eth / Measurable Data Token
if address == b"\x94\x7a\xeb\x02\x30\x43\x91\xf8\xfb\xe5\xb2\x5d\x7d\x98\xd6\x49\xb5\x7b\x17\x88":
return TokenInfo("MDX", 18) # eth / Mandala Exchange Token
if address == b"\x66\x52\xfa\x20\x1b\x6b\xbb\xc0\xb5\xb0\xad\x3f\x57\x02\xb2\xb9\x84\x9c\xc8\x30":
return TokenInfo("MEDCASH", 4) # eth / MEDCASH
if address == b"\xfd\x1e\x80\x50\x8f\x24\x3e\x64\xce\x23\x4e\xa8\x8a\x5f\xd2\x82\x7c\x71\xd4\xb7":
return TokenInfo("MEDX", 8) # eth / MediBloc [ERC20]
if address == b"\xd5\x52\x5d\x39\x78\x98\xe5\x50\x20\x75\xea\x5e\x83\x0d\x89\x14\xf6\xf0\xaf\xfe":
@ -1701,14 +1701,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("MITH", 18) # eth / Mithril
if address == b"\x4a\x52\x7d\x8f\xc1\x3c\x52\x03\xab\x24\xba\x09\x44\xf4\xcb\x14\x65\x8d\x1d\xb6":
return TokenInfo("MITX", 18) # eth / Morpheus Infrastructure Token
if address == b"\x9f\x8f\x72\xaa\x93\x04\xc8\xb5\x93\xd5\x55\xf1\x2e\xf6\x58\x9c\xc3\xa5\x79\xa2":
return TokenInfo("MKR", 18) # eth / MakerDAO
if address == b"\x79\x39\x88\x2b\x54\xfc\xf0\xbc\xae\x6b\x53\xde\xc3\x9a\xd6\xe8\x06\x17\x64\x42":
return TokenInfo("MKT", 8) # eth / Mikado
if address == b"\xec\x67\x00\x5c\x4e\x49\x8e\xc7\xf5\x5e\x09\x2b\xd1\xd3\x5c\xbc\x47\xc9\x18\x92":
return TokenInfo("MLN (new)", 18) # eth / Melonport
if address == b"\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1":
return TokenInfo("[deprecated] MLN (old)", 18) # eth / Melonport
if address == b"\x6b\x4c\x7a\x5e\x3f\x0b\x99\xfc\xd8\x3e\x9c\x08\x9b\xdd\xd6\xc7\xfc\xe5\xc6\x11":
return TokenInfo("MM", 18) # eth / Million
if address == b"\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46":
@ -1825,8 +1819,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("NOAH", 18) # eth / Noah Coin
if address == b"\xf4\xfa\xea\x45\x55\x75\x35\x4d\x26\x99\xbc\x20\x9b\x0a\x65\xca\x99\xf6\x99\x82":
return TokenInfo("NOBS", 18) # eth / No BS Crypto
if address == b"\x64\x3b\x68\x70\xbe\xab\xee\x94\x1b\x92\x60\xa0\xa8\x78\xbc\xf4\xa6\x1f\xb0\xf1":
return TokenInfo("NONE", 0) # eth / None
if address == b"\x00\x27\x44\x9b\xf0\x88\x7c\xa3\xe4\x31\xd2\x63\xff\xde\xfb\x24\x4d\x95\xb5\x55":
return TokenInfo("NOT", 18) # eth / Token Not
if address == b"\xec\x46\xf8\x20\x7d\x76\x60\x12\x45\x4c\x40\x8d\xe2\x10\xbc\xbc\x22\x43\xe7\x1c":
@ -2153,8 +2145,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("RBX", 18) # eth / RBX
if address == b"\xf9\x70\xb8\xe3\x6e\x23\xf7\xfc\x3f\xd7\x52\xee\xa8\x6f\x8b\xe8\xd8\x33\x75\xa6":
return TokenInfo("RCN", 18) # eth / Ripio Credit Network
if address == b"\x25\x5a\xa6\xdf\x07\x54\x0c\xb5\xd3\xd2\x97\xf0\xd0\xd4\xd8\x4c\xb5\x2b\xc8\xe6":
return TokenInfo("RDN", 18) # eth / Raiden Network
if address == b"\xd9\x67\xd9\xf9\x41\xcd\x31\x6a\xb2\x38\xd3\xee\x76\x1f\x80\xb7\xca\xec\x78\x19":
return TokenInfo("RDV", 18) # eth / Rendezvous
if address == b"\x76\x7b\xa2\x91\x5e\xc3\x44\x01\x5a\x79\x38\xe3\xee\xdf\xec\x27\x85\x19\x5d\x05":
@ -2177,10 +2167,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("REMI", 18) # eth / REMI
if address == b"\x40\x8e\x41\x87\x6c\xcc\xdc\x0f\x92\x21\x06\x00\xef\x50\x37\x26\x56\x05\x2a\x38":
return TokenInfo("REN", 18) # eth / Republic Token
if address == b"\x19\x85\x36\x5e\x9f\x78\x35\x9a\x9b\x6a\xd7\x60\xe3\x24\x12\xf4\xa4\x45\xe8\x62":
return TokenInfo("REP", 18) # eth / Augur
if address == b"\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6":
return TokenInfo("[deprecated] REP", 18) # eth / Augur
if address == b"\x22\x16\x57\x77\x68\x46\x89\x09\x89\xa7\x59\xba\x29\x73\xe4\x27\xdf\xf5\xc9\xbb":
return TokenInfo("REPv2", 18) # eth / Reputation
if address == b"\x8f\x82\x21\xaf\xbb\x33\x99\x8d\x85\x84\xa2\xb0\x57\x49\xba\x73\xc3\x7a\x93\x8a":
@ -2205,8 +2191,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("RIYA", 8) # eth / Etheriya
if address == b"\x10\x6a\xa4\x92\x95\xb5\x25\xfc\xf9\x59\xaa\x75\xec\x3f\x7d\xcb\xf5\x35\x2f\x1c":
return TokenInfo("RKT", 18) # eth / Rock
if address == b"\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75":
return TokenInfo("RLC", 9) # eth / IEx.ec
if address == b"\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48":
return TokenInfo("RLT", 10) # eth / RouletteToken
if address == b"\xbe\x99\xb0\x97\x09\xfc\x75\x3b\x09\xbc\xf5\x57\xa9\x92\xf6\x60\x5d\x59\x97\xb0":
@ -2241,6 +2225,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("RPE", 18) # eth / REPE
if address == b"\xb4\xef\xd8\x5c\x19\x99\x9d\x84\x25\x13\x04\xbd\xa9\x9e\x90\xb9\x23\x00\xbd\x93":
return TokenInfo("RPL", 18) # eth / Rocket Pool
if address == b"\x32\x06\x23\xb8\xe4\xff\x03\x37\x39\x31\x76\x9a\x31\xfc\x52\xa4\xe7\x8b\x5d\x70":
return TokenInfo("RSR", 18) # eth / Reserve Rights
if address == b"\xec\x49\x1c\x10\x88\xea\xe9\x92\xb7\xa2\x14\xef\xb0\xa2\x66\xad\x09\x27\xa7\x2a":
return TokenInfo("RTB", 18) # eth / AB-Chain RTB
if address == b"\x7a\x55\x99\xb9\x7e\x8c\x4a\xbb\x5d\xd0\x6e\xba\x0e\x9d\x1f\x75\xaf\x81\x8d\xb9":
@ -2307,6 +2293,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("SETS", 18) # eth / Sensitrust Token
if address == b"\x68\x47\x3d\xc4\xb7\xa4\xb0\x86\x7f\xd7\xc5\xb9\xa9\x82\xfe\xa4\x07\xda\xd3\x20":
return TokenInfo("sEUR", 18) # eth / Synth sEUR
if address == b"\xaf\x50\xf8\xbe\xc1\xdb\xec\x01\x3b\x70\x25\xdb\x44\x4d\xa0\x19\xc2\xf5\xd4\x88":
return TokenInfo("SEV", 18) # eth / SeveraDAO
if address == b"\x98\xf5\xe9\xb7\xf0\xe3\x39\x56\xc0\x44\x3e\x81\xbf\x7d\xeb\x8b\x5b\x1e\xd5\x45":
return TokenInfo("SEXY", 18) # eth / Sexy Token
if address == b"\xed\x08\x49\xbf\x46\xcf\xb9\x84\x5a\x2d\x90\x0a\x0a\x4e\x59\x3f\x2d\xd3\x67\x3c":
@ -2525,6 +2513,8 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("SXUT", 18) # eth / Spectre.ai U-Token
if address == b"\x10\xb1\x23\xfd\xdd\xe0\x03\x24\x31\x99\xaa\xd0\x35\x22\x06\x5d\xc0\x58\x27\xa0":
return TokenInfo("SYN", 18) # eth / Synapse
if address == b"\x46\xea\xf7\x5e\x6d\x39\x17\x08\xb7\xf1\xa0\xd5\x68\x75\xd9\x08\x44\x11\x95\x21":
return TokenInfo("SYS", 18) # eth / Syscoin
if address == b"\x3a\x0d\x74\x6b\x3e\xa1\xd8\xcc\xdf\x19\xad\x91\x59\x13\xbd\x68\x39\x11\x33\xca":
return TokenInfo("SYSX", 8) # eth / SyscoinToken
if address == b"\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c":
@ -3395,6 +3385,10 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("WINGS", 18) # eth / WINGS
if address == b"\x1b\x22\xc3\x2c\xd9\x36\xcb\x97\xc2\x8c\x56\x90\xa0\x69\x5a\x82\xab\xf6\x88\xe6":
return TokenInfo("WISH", 18) # eth / MyWish
if address == b"\xd6\x4d\xee\xa5\xf2\x49\x34\xe3\xa1\xaa\x75\x29\x12\xae\xe8\xff\xd8\x30\x0c\x3f":
return TokenInfo("WLKR", 18) # eth / WLKR Innovation Index
if address == b"\xc9\x02\x06\xab\x21\xbd\xbf\x5e\x92\xaf\xf4\xe6\xb5\xf0\x97\xb6\x5b\x0e\xcc\x06":
return TokenInfo("WLKRR", 18) # eth / Walker
if address == b"\x68\x5e\xd3\x90\xb1\x6a\xc9\xdf\x9a\xb9\x70\x72\x94\xa4\x2a\x10\x7c\xfb\x62\xaf":
return TokenInfo("WMA", 18) # eth / weeMarketplaceAccessToken
if address == b"\xbf\xbe\x53\x32\xf1\x72\xd7\x78\x11\xbc\x6c\x27\x28\x44\xf3\xe5\x4a\x7b\x23\xbb":
@ -3561,8 +3555,6 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("ZMN", 18) # eth / ZMINE
if address == b"\xb5\xb8\xf5\x61\x6f\xe4\x2d\x5c\xec\xa3\xe8\x7f\x3f\xdd\xbd\xd8\xf4\x96\xd7\x60":
return TokenInfo("ZPR", 18) # eth / ZPER
if address == b"\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98":
return TokenInfo("ZRX", 18) # eth / 0x Project
if address == b"\xe3\x86\xb1\x39\xed\x37\x15\xca\x4b\x18\xfd\x52\x67\x1b\xdc\xea\x1c\xdf\xe4\xb1":
return TokenInfo("ZST", 8) # eth / Zeus Exchange
if address == b"\xe8\xf9\xfa\x97\x7e\xa5\x85\x59\x1d\x9f\x39\x46\x81\x31\x8c\x16\x55\x25\x77\xfb":
@ -3578,27 +3570,17 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("ILSC", 2) # rop / IsraCoin
if address == b"\x4c\x57\x2f\xbc\x03\xd4\xa2\xb6\x83\xcf\x4f\x10\xff\xdc\xaf\xd0\x08\x85\xe1\x08":
return TokenInfo("MEWV5", 9) # rop / MEW V5 Test Token
if address == b"\xfd\x5a\x69\xa1\x30\x95\x95\xff\x51\x21\x55\x3f\x52\xc8\xa5\xb2\xb1\xb3\x10\x31":
return TokenInfo("NONE", 0) # rop / None
if address == b"\x73\x14\xdc\x4d\x77\x94\xb5\xe7\x89\x42\x12\xca\x15\x56\xae\x8e\x3d\xe5\x86\x21":
return TokenInfo("RLC", 9) # rop / iExec RLC
if address == b"\xaa\x1d\x9d\x07\x88\xda\xca\x9a\x30\x11\x1d\x12\xaa\x0d\x98\x09\x0f\x02\xea\x30":
return TokenInfo("RCL", 18) # rop / RascalCoin
if chain_id == 4:
if address == b"\xe2\x78\x26\xee\x77\x8b\x6f\x78\xa4\x9a\x68\x6d\xa7\xd6\x4f\x6e\x7b\x08\x4a\x4f":
return TokenInfo("BHNT", 0) # rin / Berlin Hack&Tell winner token
if address == b"\x8b\x65\xd4\xb7\xee\x3f\xff\xa9\x86\xc5\x77\xf0\xf4\xb7\x0a\x21\xba\xe3\xdd\x54":
return TokenInfo("CTGA", 18) # rin / Convenient To Go
if address == b"\x27\x5a\x5b\x34\x65\x99\xb5\x69\x17\xe7\xb1\xc9\xde\x01\x9d\xcf\x9e\xad\x86\x1a":
return TokenInfo("KC", 18) # rin / Karma Token
if address == b"\x64\x75\xa7\xfa\x6e\xd2\xd5\x18\x0f\x0e\x0a\x07\xc2\xd9\x51\xd1\x2c\x0e\xdb\x91":
return TokenInfo("NONE", 0) # rin / None
if address == b"\x12\xfe\x17\x4c\x09\x7f\x6b\x3e\x87\x6b\x3b\x06\x0c\x90\x61\xf4\xb9\xde\xbb\x80":
return TokenInfo("PPD", 18) # rin / PP Donation
if address == b"\x2d\x42\x7d\x9e\x53\x5e\x43\x82\x60\x6b\x93\x29\x0d\xcc\x13\xa5\xe9\xa6\x94\xbe":
return TokenInfo("qwe", 18) # rin / qweToken
if address == b"\x36\x15\x75\x70\x11\x11\x25\x60\x52\x15\x36\x25\x8c\x1e\x73\x25\xae\x3b\x48\xae":
return TokenInfo("RDN", 18) # rin / Raiden
if address == b"\xf1\xe6\xad\x3a\x7e\xf0\xc8\x6c\x91\x5f\x0f\xed\xf8\x0e\xd8\x51\x80\x9b\xea\x90":
return TokenInfo("RLC", 9) # rin / iExec RLC
if address == b"\x0a\x05\x7a\x87\xce\x9c\x56\xd7\xe3\x36\xb4\x17\xc7\x9c\xf3\x0e\x8d\x27\x86\x0b":
return TokenInfo("WALL", 15) # rin / WALLETH Community-Token
if chain_id == 8:
@ -3608,10 +3590,26 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
return TokenInfo("CEFS", 8) # ubq / CEFS
if address == b"\x94\xad\x7e\x41\xc1\xd4\x40\x22\xc4\xf4\x7c\xb1\xba\x01\x9f\xd1\xa0\x22\xc5\x36":
return TokenInfo("DOT", 8) # ubq / DOT
if address == b"\xcf\x32\x22\xb7\xfd\xa7\xa7\x56\x3b\x9e\x1e\x6c\x96\x6b\xea\xd0\x4a\xc2\x3c\x36":
return TokenInfo("ESCH", 18) # ubq / Escher
if address == b"\x50\x06\x84\xce\x0d\x4f\x04\xab\xed\xff\x3e\x54\xfc\xf8\xac\xc5\xe6\xcf\xc4\xbd":
return TokenInfo("GEO", 8) # ubq / GeoCoin
if address == b"\x08\x26\x18\x0a\x4c\x98\x1d\x50\x95\xcb\x5c\x48\xbb\x2a\x09\x8a\x44\xcf\x6f\x73":
return TokenInfo("GRANS", 18) # ubq / 10grans
if address == b"\x78\x45\xfc\xbe\x28\xac\x19\xab\x7e\xc1\xc1\xd9\x67\x4e\x34\xfd\xcb\x49\x17\xdb":
return TokenInfo("INK", 18) # ubq / INK
if address == b"\x4b\x48\x99\xa1\x0f\x3e\x50\x7d\xb2\x07\xb0\xee\x24\x26\x02\x9e\xfa\x16\x8a\x67":
return TokenInfo("QWARK", 8) # ubq / QWARK
if address == b"\x5e\x17\x15\xbb\x79\x80\x5b\xd6\x72\x72\x97\x60\xb3\xf7\xf3\x4d\x6f\x48\x50\x98":
return TokenInfo("RICKS", 8) # ubq / RICKS
if address == b"\x49\x7e\x20\x58\x6f\x86\xc3\x55\x92\xff\x8f\x65\xcd\xe9\x4f\x29\x65\x14\xc3\x87":
return TokenInfo("SNARG", 0) # ubq / Snarg01
if address == b"\x20\xe3\xdd\x74\x6d\xdf\x51\x9b\x23\xff\xbb\xb6\xda\x7a\x5d\x33\xea\x63\x49\xd6":
return TokenInfo("SPHR", 8) # ubq / Sphere
if address == b"\x40\x2c\x2c\x3a\xce\xeb\x52\xb8\x65\x4a\x06\x31\x01\x2c\xed\x49\xcb\xc9\xbd\xc4":
return TokenInfo("SPHRC", 18) # ubq / Sphere Cubed
if address == b"\xcf\x82\x3e\xb6\xf6\x2a\x30\xed\xb0\x05\xb9\x13\x83\xe2\xfa\x36\x4d\xd7\x53\xdc":
return TokenInfo("TGE1", 18) # ubq / Ubiq TGE 1
if chain_id == 30:
if address == b"\xd5\x2d\xa6\x36\x89\x54\x39\x24\xdc\xa6\x6b\xcb\xe2\xe2\xea\x59\x9c\x45\xd5\x75":
return TokenInfo("ARSCB", 18) # rsk / Pesos Argentinos PagoLinea
@ -3692,30 +3690,10 @@ def token_by_chain_address(chain_id: int, address: bytes) -> TokenInfo:
if chain_id == 42:
if address == b"\x86\x67\x55\x92\x54\x24\x1d\xde\xd4\xd1\x13\x92\xf8\x68\xd7\x20\x92\x76\x53\x67":
return TokenInfo("Aeternity", 18) # kov / Aeternity
if address == b"\xc4\x37\x5b\x7d\xe8\xaf\x5a\x38\xa9\x35\x48\xeb\x84\x53\xa4\x98\x22\x2c\x4f\xf2":
return TokenInfo("DAI", 18) # kov / RadarRelay test Dai Stablecoin v1.0
if address == b"\xee\xe3\x87\x06\x57\xe4\x71\x66\x70\xf1\x85\xdf\x08\x65\x2d\xd8\x48\xfe\x8f\x7e":
return TokenInfo("DGD", 18) # kov / RadarRelay test Digix DAO Token
if address == b"\x47\x33\x65\x9a\x5c\xb7\x89\x6a\x65\xc9\x18\xad\xd6\xf5\x9c\x51\x48\xfb\x5f\xfa":
return TokenInfo("GAV", 6) # kov / GavCoin
if address == b"\xef\x7f\xff\x64\x38\x9b\x81\x4a\x94\x6f\x3e\x92\x10\x55\x13\x70\x5c\xa6\xb9\x90":
return TokenInfo("GNT", 18) # kov / RadarRelay test Golem Network Token
if address == b"\x3c\x67\xf7\xd4\xde\xcf\x77\x95\x22\x5f\x51\xb5\x41\x34\xf8\x11\x37\x38\x5f\x83":
return TokenInfo("GUP", 3) # kov / GUP
if address == b"\x1d\xad\x47\x83\xcf\x3f\xe3\x08\x5c\x14\x26\x15\x7a\xb1\x75\xa6\x11\x9a\x04\xba":
return TokenInfo("MKR", 18) # kov / RadarRelay test MakerDAO
if address == b"\xaa\xf6\x4b\xfc\xc3\x2d\x0f\x15\x87\x3a\x02\x16\x3e\x7e\x50\x06\x71\xa4\xff\xcd":
return TokenInfo("MKR", 18) # kov / MakerDAO
if address == b"\x32\x3b\x5d\x4c\x32\x34\x5c\xed\x77\x39\x3b\x35\x30\xb1\xee\xd0\xf3\x46\x42\x9d":
return TokenInfo("MLN", 18) # kov / RadarRelay test Melon Tokens
if address == b"\xb1\x88\x45\xc2\x60\xf6\x80\xd5\xb9\xd8\x46\x49\x63\x88\x13\xe3\x42\xe4\xf8\xc9":
return TokenInfo("REP", 18) # kov / RadarRelay test Augur Reputation Token
if address == b"\xc5\x75\x38\x84\x6e\xc4\x05\xea\x25\xde\xb0\x0e\x0f\x9b\x29\xa4\x32\xd5\x35\x07":
return TokenInfo("RLC", 9) # kov / iExec RLC
if address == b"\x4a\x6e\x6c\x38\x68\xa2\x79\xe1\xd9\x04\x7b\x42\xc3\xfb\x35\x6f\xf4\x68\x00\x03":
return TokenInfo("TIB", 18) # kov / ThibCoin
if address == b"\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70":
return TokenInfo("ZRX", 18) # kov / RadarRelay test 0x Protocol Token
if chain_id == 61:
if address == b"\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb":
return TokenInfo("BEC", 8) # etc / BEC

@ -43,7 +43,7 @@ class TestWriters(unittest.TestCase):
b = bytearray()
writers.write_tx_input_check(b, inp)
self.assertEqual(len(b), 32 + 4 + 4 + 1 + 4 + 4 + 4 + 8 + 26)
self.assertEqual(len(b), 4 + 4 + 32 + 4 + 11 + 4 + 4 + 1 + 8 + 1 + 1 + 1 + 4 + 26)
for bad_prevhash in (b"", b"x", b"hello", b"x" * 33):
inp.prev_hash = bad_prevhash

@ -286,10 +286,10 @@ set to `tx.extra_data_chunk`.
Trezor sets `request_type` to `TXORIGINPUT`. `request_details.tx_hash` is the
transaction hash of the original transaction.
Host must respond with a `TxAckInput` message. All relevant data must be set in
The host must respond with a `TxAckInput` message. All relevant data must be set in
`tx.input`. The derivation path and `script_type` are mandatory for all original
internal inputs. For each original transaction, one of its original internal inputs must
be accompanied with a valid signature in the `script_sig` and/or `witness` fields.
internal inputs. All original internal inputs must also be accompanied with full
transaction signature data in the `script_sig` and/or `witness` fields.
### Original transaction output

@ -1 +0,0 @@
Avoid accidental build with broken stack protector

@ -1 +0,0 @@
Compress firmware verification coordinates to be able link bootloader into preallocated space.

@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 1.11.0 [May 2022]
### Added
- Bootloader will report version of installed firmware. [#2231]
### Fixed
- Compress firmware verification coordinates to be able link bootloader into preallocated space. [#1884]
### Security
- Erase storage when downgrading below fix_version.
- Avoid accidental build with broken stack protector [#1642]
## 1.10.0 [May 2021]
### Added
@ -112,3 +125,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Initial import of code.
[#1461]: https://github.com/trezor/trezor-firmware/pull/1461
[#1642]: https://github.com/trezor/trezor-firmware/pull/1642
[#1884]: https://github.com/trezor/trezor-firmware/pull/1884
[#2231]: https://github.com/trezor/trezor-firmware/pull/2231

@ -156,6 +156,51 @@ static secbool readprotobufint(const uint8_t **ptr, uint32_t *result) {
return sectrue;
}
/** Reverse-endian version comparison
*
* Versions are loaded from the header via a packed struct image_header. A
* version is represented as a single uint32_t. Arm is natively little-endian,
* but the version is actually stored as four bytes in major-minor-patch-build
* order. This function implements `cmp` with "lowest" byte first.
*/
static int version_compare(const uint32_t vera, const uint32_t verb) {
int a, b; // signed temp values so that we can safely return a signed result
a = vera & 0xFF;
b = verb & 0xFF;
if (a != b) return a - b;
a = (vera >> 8) & 0xFF;
b = (verb >> 8) & 0xFF;
if (a != b) return a - b;
a = (vera >> 16) & 0xFF;
b = (verb >> 16) & 0xFF;
if (a != b) return a - b;
a = (vera >> 24) & 0xFF;
b = (verb >> 24) & 0xFF;
return a - b;
}
static int should_keep_storage(int old_was_signed,
uint32_t fix_version_current) {
// if the current firmware is unsigned, always erase storage
if (SIG_OK != old_was_signed) return SIG_FAIL;
const image_header *new_hdr = (const image_header *)FW_HEADER;
// if the new header is unsigned, erase storage
if (SIG_OK != signatures_new_ok(new_hdr, NULL)) return SIG_FAIL;
// if the new header hashes don't match flash contents, erase storage
if (SIG_OK != check_firmware_hashes(new_hdr)) return SIG_FAIL;
// going from old-style header to new-style is always an upgrade, keep storage
if (firmware_present_old()) return SIG_OK;
// if the current fix_version is higher than the new one, erase storage
if (version_compare(new_hdr->version, fix_version_current) < 0) {
return SIG_FAIL;
}
return SIG_OK;
}
static void rx_callback(usbd_device *dev, uint8_t ep) {
(void)ep;
static uint16_t msg_id = 0xFFFF;
@ -163,6 +208,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) {
static uint32_t w;
static int wi;
static int old_was_signed;
static uint32_t fix_version_current = 0xffffffff;
if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return;
@ -235,10 +281,13 @@ static void rx_callback(usbd_device *dev, uint8_t ep) {
(const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
old_was_signed =
signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr);
fix_version_current = hdr->fix_version;
} else if (firmware_present_old()) {
old_was_signed = signatures_old_ok();
fix_version_current = 0;
} else {
old_was_signed = SIG_FAIL;
fix_version_current = 0xffffffff;
}
erase_code_progress();
send_msg_success(dev);
@ -388,8 +437,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) {
// 1) old firmware was unsigned or not present
// 2) signatures are not OK
// 3) hashes are not OK
if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) ||
SIG_OK != check_firmware_hashes(hdr)) {
if (SIG_OK != should_keep_storage(old_was_signed, fix_version_current)) {
// erase storage
erase_storage();
// check erasure

@ -37,7 +37,7 @@ static void send_msg_failure(usbd_device *dev, uint8_t code) {
static void send_msg_features(usbd_device *dev) {
uint8_t response[64];
memzero(response, sizeof(response));
// response: Features message (id 17), payload len 26
// response: Features message (id 17), payload len 26 / 41
// - vendor = "trezor.io"
// - major_version = VERSION_MAJOR
// - minor_version = VERSION_MINOR
@ -45,28 +45,62 @@ static void send_msg_features(usbd_device *dev) {
// - bootloader_mode = True
// - firmware_present = True/False
// - model = "1"
memcpy(response,
// header
"?##"
// msg_id
"\x00\x11"
// msg_size
"\x00\x00\x00\x1a"
// data
"\x0a"
"\x09"
"trezor.io"
"\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR
"\x20" VERSION_PATCH_CHAR
"\x28"
"\x01"
"\x90\x01"
"\x00"
"\xaa"
"\x01\x01"
"1",
35);
response[30] = firmware_present_new() ? 0x01 : 0x00;
// ? fw_version_major = version_major
// ? fw_version_minor = version_minor
// ? fw_version_patch = version_patch
const bool firmware_present = firmware_present_new();
const image_header *current_hdr = (const image_header *)FLASH_FWHEADER_START;
uint32_t version = firmware_present ? current_hdr->version : 0;
// clang-format off
const uint8_t feature_bytes[] = {
0x0a, // vendor field
0x09, // vendor length
't', 'r', 'e', 'z', 'o', 'r', '.', 'i', 'o',
0x10, VERSION_MAJOR,
0x18, VERSION_MINOR,
0x20, VERSION_PATCH,
0x28, 0x01, // bootloader_mode
0x90, 0x01, // firmware_present field
firmware_present ? 0x01 : 0x00,
0xaa, 0x01, // model field
0x01, // model length
'1',
};
const uint8_t version_bytes[] = {
// fw_version_major
0xb0, 0x01, version & 0xff,
// fw_version_minor
0xb8, 0x01, (version >> 8) & 0xff,
// fw_version_patch
0xc0, 0x01, (version >> 16) & 0xff,
};
uint8_t header_bytes[] = {
// header
'?', '#', '#',
// msg_id
0x00, 0x11,
// msg_size
0x00, 0x00, 0x00, sizeof(feature_bytes) + (firmware_present ? sizeof(version_bytes) : 0),
};
// clang-format on
// Check that the response will fit into an USB packet, and also that the
// sizeof expression above fits into a single byte
_Static_assert(
sizeof(feature_bytes) + sizeof(version_bytes) + sizeof(header_bytes) <=
64,
"Features response too long");
memcpy(response, header_bytes, sizeof(header_bytes));
memcpy(response + sizeof(header_bytes), feature_bytes, sizeof(feature_bytes));
if (firmware_present) {
memcpy(response + sizeof(header_bytes) + sizeof(feature_bytes),
version_bytes, sizeof(version_bytes));
}
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
}

@ -1,7 +1,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 10
#define VERSION_PATCH 1
#define VERSION_MINOR 11
#define VERSION_PATCH 0
#define VERSION_MAJOR_CHAR "\x01"
#define VERSION_MINOR_CHAR "\x0A"
#define VERSION_PATCH_CHAR "\x01"
#define VERSION_MINOR_CHAR "\x0B"
#define VERSION_PATCH_CHAR "\x00"

@ -1 +0,0 @@
Ensure input's script type and path match the scriptPubKey.

@ -1 +0,0 @@
Trezor will refuse to sign UTXOs that do not match the provided derivation path (e.g., transactions belonging to a different wallet, or synthetic transaction inputs).

@ -1 +0,0 @@
Show "signature is valid" dialog when VerifyMessage succeeds.

@ -1 +0,0 @@
Support Zcash version 5 transaction format.

@ -1 +0,0 @@
Fix domain-only EIP-712 hashes (i.e. when `primaryType`=`EIP712Domain`)

@ -1 +0,0 @@
Add extra check for Taproot scripts validity

@ -1 +0,0 @@
Support Electrum signatures in VerifyMessage.

@ -1 +0,0 @@
Fix legacy technical debt in USB handling (readability and FSM unwanted states).

@ -1 +0,0 @@
\[emulator] Added support for `DebugLinkReseedRandom`.

@ -1 +0,0 @@
\[emulator] Removed support for /dev/urandom or custom entropy source.

@ -1 +0,0 @@
Support unverified external inputs.

@ -1 +0,0 @@
GAME, NIX and POLIS support

@ -1 +0,0 @@
Add firmware hashing functionality.

@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 1.11.1 [18th May 2022]
### Added
- Show "signature is valid" dialog when VerifyMessage succeeds. [#1880]
- Add extra check for Taproot scripts validity. [#2077]
- Support Electrum signatures in VerifyMessage. [#2100]
- \[emulator] Added support for `DebugLinkReseedRandom`. [#2115]
- Support unverified external inputs. [#2144]
- Support Zcash version 5 transaction format. [#2031]
- Add firmware hashing functionality. [#2239]
### Changed
- Ensure input's script type and path match the scriptPubKey. [#1018]
- Included bootloader 1.11.0.
### Removed
- \[emulator] Removed support for /dev/urandom or custom entropy source. [#2115]
- GAME, NIX and POLIS support. [#2181]
### Fixed
- Fix domain-only EIP-712 hashes (i.e. when `primaryType`=`EIP712Domain`). [#2036]
- Fix legacy technical debt in USB handling (readability and FSM unwanted states). [#2107]
### Security
- Strict path validations for altcoins.
- Fix soft-lock bypass vulnerability.
- Make Bitcoin path checks as strict as in Trezor T.
### Incompatible changes
- Trezor will refuse to sign UTXOs that do not match the provided derivation path (e.g., transactions belonging to a different wallet, or synthetic transaction inputs). [#1018]
## 1.10.5 [19th January 2022]
### Added
@ -459,6 +492,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#131]: https://github.com/trezor/trezor-firmware/pull/131
[#965]: https://github.com/trezor/trezor-firmware/pull/965
[#1018]: https://github.com/trezor/trezor-firmware/pull/1018
[#1030]: https://github.com/trezor/trezor-firmware/pull/1030
[#1098]: https://github.com/trezor/trezor-firmware/pull/1098
[#1105]: https://github.com/trezor/trezor-firmware/pull/1105
@ -497,5 +531,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1854]: https://github.com/trezor/trezor-firmware/pull/1854
[#1857]: https://github.com/trezor/trezor-firmware/pull/1857
[#1872]: https://github.com/trezor/trezor-firmware/pull/1872
[#1880]: https://github.com/trezor/trezor-firmware/pull/1880
[#1897]: https://github.com/trezor/trezor-firmware/pull/1897
[#1985]: https://github.com/trezor/trezor-firmware/pull/1985
[#2031]: https://github.com/trezor/trezor-firmware/pull/2031
[#2036]: https://github.com/trezor/trezor-firmware/pull/2036
[#2077]: https://github.com/trezor/trezor-firmware/pull/2077
[#2100]: https://github.com/trezor/trezor-firmware/pull/2100
[#2107]: https://github.com/trezor/trezor-firmware/pull/2107
[#2115]: https://github.com/trezor/trezor-firmware/pull/2115
[#2144]: https://github.com/trezor/trezor-firmware/pull/2144
[#2181]: https://github.com/trezor/trezor-firmware/pull/2181
[#2239]: https://github.com/trezor/trezor-firmware/pull/2239

@ -179,6 +179,8 @@ bl_data.h: bl_data.py bootloader.dat
@printf " PYTHON bl_data.py\n"
$(Q)$(PYTHON) bl_data.py
header.o: version.h
clean::
rm -f bl_data.h
find -maxdepth 1 -name "*.mako" | sed 's/.mako$$//' | xargs rm -f

@ -132,6 +132,12 @@ static int known_bootloader(int r, const uint8_t *hash) {
"\xb9\xc7\xf6\x03\xcd\xc7\x30\xe7\x30\x78\x50\xa3\xf4\xd6\x2a\x5c",
32))
return 1; // 1.10.0 shipped with fw 1.10.0
if (0 ==
memcmp(hash,
"\xfa\x12\xa4\x4f\xa0\x5f\xd1\xd2\x05\x39\x35\x8b\x54\xf3\x01\xce"
"\xe4\xc3\x21\x9c\x9f\x1b\xb3\xa5\x77\x2f\xfd\x60\x9a\xf9\xe8\xe2",
32))
return 1; // 1.11.0 shipped with fw 1.11.1
return 0;
}
#endif

Binary file not shown.

@ -431,7 +431,10 @@ void session_clearCache(Session *session) {
session->seedCached = false;
}
void config_lockDevice(void) { storage_lock(); }
void config_lockDevice(void) {
fsm_abortWorkflows();
storage_lock();
}
static void get_u2froot_callback(uint32_t iter, uint32_t total) {
layoutProgress(_("Updating"), 1000 * iter / total);

@ -36,10 +36,6 @@
#include "cash_addr.h"
#endif
#define PATH_MAX_ACCOUNT 100
#define PATH_MAX_CHANGE 1
#define PATH_MAX_ADDRESS_INDEX 1000000
uint32_t ser_length(uint32_t len, uint8_t *out) {
if (len < 253) {
out[0] = len & 0xFF;
@ -491,231 +487,204 @@ static bool check_cointype(const CoinInfo *coin, uint32_t slip44, bool full) {
bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
uint32_t address_n_count, const uint32_t *address_n,
bool has_multisig, CoinPathCheckLevel level) {
// For level BASIC this function checks that a coin without strong replay
// protection doesn't access paths that are known to be used by another coin.
// Used by SignTx to ensure that a user cannot be coerced into signing a
// testnet transaction or a Litecoin transaction which in fact spends Bitcoin.
// For level KNOWN this function checks that the path is a recognized path for
// the given coin. Used by GetAddress to prevent ransom attacks where a user
// could be coerced to use an address with an unenumerable path.
// For level SCRIPT_TYPE this function makes the same checks as in level
// KNOWN, but includes script type checks.
const bool check_known = (level >= CoinPathCheckLevel_KNOWN);
const bool check_script_type = (level >= CoinPathCheckLevel_SCRIPT_TYPE);
bool has_multisig, bool full_check) {
// This function checks that the path is a recognized path for the given coin.
// Used by GetAddress to prevent ransom attacks where a user could be coerced
// to use an address with an unenumerable path and used by SignTx to ensure
// that a user cannot be coerced into signing a testnet transaction or a
// Litecoin transaction which in fact spends Bitcoin. If full_check is true,
// then this function also checks that the path fully matches the script type
// and coin type. This is used to determine whether a warning should be shown.
if (address_n_count == 0) {
return false;
}
bool valid = true;
// m/44' : BIP44 Legacy
// m / purpose' / coin_type' / account' / change / address_index
if (address_n_count > 0 && address_n[0] == (0x80000000 + 44)) {
if (check_known) {
valid = valid && (address_n_count == 5);
} else {
valid = valid && (address_n_count >= 2);
}
valid = valid && check_cointype(coin, address_n[1], check_known);
if (check_script_type) {
if (address_n[0] == PATH_HARDENED + 44) {
valid = valid && (address_n_count == 5);
valid = valid && check_cointype(coin, address_n[1], full_check);
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && (script_type == InputScriptType_SPENDADDRESS);
valid = valid && (!has_multisig);
}
if (check_known) {
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
}
return valid;
}
if (address_n_count > 0 && address_n[0] == (0x80000000 + 45)) {
if (check_script_type) {
valid = valid && has_multisig;
}
if (address_n[0] == PATH_HARDENED + 45) {
if (address_n_count == 4) {
// m/45' - BIP45 Copay Abandoned Multisig P2SH
// m / purpose' / cosigner_index / change / address_index
// Patterns without a coin_type field must be treated as Bitcoin paths.
valid = valid && check_cointype(coin, SLIP44_BITCOIN, check_known);
if (check_script_type) {
valid = valid && (script_type == InputScriptType_SPENDMULTISIG);
}
if (check_known) {
valid = valid && (address_n[1] <= 100);
valid = valid && (address_n[2] <= PATH_MAX_CHANGE);
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
}
valid = valid && check_cointype(coin, SLIP44_BITCOIN, false);
valid = valid && (address_n[1] <= 100);
valid = valid && (address_n[2] <= PATH_MAX_CHANGE);
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
} else if (address_n_count == 5) {
// Unchained Capital compatibility pattern. Will be removed in the
// future.
// m / 45' / coin_type' / account' / [0-1000000] / address_index
valid = valid && check_cointype(coin, address_n[1], check_known);
if (check_script_type) {
valid = valid && (script_type == InputScriptType_SPENDADDRESS ||
script_type == InputScriptType_SPENDMULTISIG);
}
if (check_known) {
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= 1000000);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
}
valid = valid && check_cointype(coin, address_n[1], full_check);
valid = valid && (address_n[2] & PATH_HARDENED);
valid =
valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= 1000000);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
} else if (address_n_count == 6) {
// Unchained Capital compatibility pattern. Will be removed in the
// future.
// m/45'/coin_type'/account'/[0-1000000]/change/address_index
// m/45'/coin_type/account/[0-1000000]/change/address_index
valid = valid &&
check_cointype(coin, PATH_HARDENED | address_n[1], full_check);
valid = valid && ((address_n[1] & PATH_HARDENED) ==
(address_n[2] & PATH_HARDENED));
valid =
valid && check_cointype(coin, 0x80000000 | address_n[1], check_known);
if (check_script_type) {
valid = valid && (script_type == InputScriptType_SPENDADDRESS ||
script_type == InputScriptType_SPENDMULTISIG);
}
if (check_known) {
valid = valid &&
((address_n[1] & 0x80000000) == (address_n[2] & 0x80000000));
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= 1000000);
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
}
valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= 1000000);
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
} else {
if (check_known) {
return false;
}
return false;
}
if (full_check) {
valid = valid && (script_type == InputScriptType_SPENDADDRESS ||
script_type == InputScriptType_SPENDMULTISIG);
valid = valid && has_multisig;
}
return valid;
}
// m/48' - BIP48 Copay Multisig P2SH
// m / purpose' / coin_type' / account' / change / address_index
// Electrum:
// m / purpose' / coin_type' / account' / type' / change / address_index
if (address_n_count > 0 && address_n[0] == (0x80000000 + 48)) {
if (check_known) {
valid = valid && (address_n_count == 5 || address_n_count == 6);
} else {
valid = valid && (address_n_count >= 2);
}
valid = valid && check_cointype(coin, address_n[1], check_known);
if (check_script_type) {
valid = valid && has_multisig;
// we do not support Multisig with Taproot yet
valid = valid && (script_type == InputScriptType_SPENDMULTISIG ||
script_type == InputScriptType_SPENDP2SHWITNESS ||
script_type == InputScriptType_SPENDWITNESS);
}
if (check_known) {
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
if (address_n_count == 5) {
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
} else if (address_n_count == 6) {
valid = valid && ((address_n[3] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[3] & 0x7fffffff) <= 3);
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
} else {
return false;
if (address_n[0] == PATH_HARDENED + 48) {
valid = valid && (address_n_count == 5 || address_n_count == 6);
valid = valid && check_cointype(coin, address_n[1], full_check);
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
if (address_n_count == 5) {
// [OBSOLETE] m/48' Copay Multisig P2SH
// m / purpose' / coin_type' / account' / change / address_index
// NOTE: this pattern is not recognized by trezor-core
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && has_multisig;
valid = valid && (script_type == InputScriptType_SPENDMULTISIG);
}
} else if (address_n_count == 6) {
// BIP-48:
// m / purpose' / coin_type' / account' / type' / change / address_index
valid = valid && (address_n[3] & PATH_HARDENED);
uint32_t type = address_n[3] & PATH_UNHARDEN_MASK;
valid = valid && (type <= 2);
valid = valid && (type == 0 || coin->has_segwit);
valid = valid && (address_n[4] <= PATH_MAX_CHANGE);
valid = valid && (address_n[5] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && has_multisig;
switch (type) {
case 0:
valid = valid && (script_type == InputScriptType_SPENDMULTISIG ||
script_type == InputScriptType_SPENDADDRESS);
break;
case 1:
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
break;
case 2:
valid = valid && (script_type == InputScriptType_SPENDWITNESS);
break;
default:
return false;
}
}
} else {
return false;
}
return valid;
}
// m/49' : BIP49 SegWit
// m / purpose' / coin_type' / account' / change / address_index
if (address_n_count > 0 && address_n[0] == (0x80000000 + 49)) {
if (address_n[0] == PATH_HARDENED + 49) {
valid = valid && coin->has_segwit;
if (check_known) {
valid = valid && (address_n_count == 5);
} else {
valid = valid && (address_n_count >= 2);
}
valid = valid && check_cointype(coin, address_n[1], check_known);
if (check_script_type) {
valid = valid && (address_n_count == 5);
valid = valid && check_cointype(coin, address_n[1], full_check);
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
}
if (check_known) {
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
}
return valid;
}
// m/84' : BIP84 Native SegWit
// m / purpose' / coin_type' / account' / change / address_index
if (address_n_count > 0 && address_n[0] == (0x80000000 + 84)) {
if (address_n[0] == PATH_HARDENED + 84) {
valid = valid && coin->has_segwit;
valid = valid && (coin->bech32_prefix != NULL);
if (check_known) {
valid = valid && (address_n_count == 5);
} else {
valid = valid && (address_n_count >= 2);
}
valid = valid && check_cointype(coin, address_n[1], check_known);
if (check_script_type) {
valid = valid && (address_n_count == 5);
valid = valid && check_cointype(coin, address_n[1], full_check);
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && (script_type == InputScriptType_SPENDWITNESS);
}
if (check_known) {
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
}
return valid;
}
// m/86' : BIP86 Taproot
// m / purpose' / coin_type' / account' / change / address_index
if (address_n_count > 0 && address_n[0] == (0x80000000 + 86)) {
if (address_n[0] == PATH_HARDENED + 86) {
valid = valid && coin->has_taproot;
valid = valid && (coin->bech32_prefix != NULL);
if (check_known) {
valid = valid && (address_n_count == 5);
} else {
valid = valid && (address_n_count >= 2);
}
valid = valid && check_cointype(coin, address_n[1], check_known);
if (check_script_type) {
valid = valid && (address_n_count == 5);
valid = valid && check_cointype(coin, address_n[1], full_check);
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
// we do not support Multisig with Taproot yet
valid = valid && !has_multisig;
valid = valid && (script_type == InputScriptType_SPENDTAPROOT);
}
if (check_known) {
valid = valid && ((address_n[2] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[2] & 0x7fffffff) <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
}
return valid;
}
// Green Address compatibility pattern. Will be removed in the future.
// m / [1,4] / address_index
if (address_n_count > 0 && (address_n[0] == 1 || address_n[0] == 4)) {
if (address_n[0] == 1 || address_n[0] == 4) {
valid = valid && (coin->coin_type == SLIP44_BITCOIN);
if (check_known) {
valid = valid && (address_n_count == 2);
valid = valid && (address_n[1] <= PATH_MAX_ADDRESS_INDEX);
valid = valid && (address_n_count == 2);
valid = valid && (address_n[1] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && (script_type != InputScriptType_SPENDTAPROOT);
}
return valid;
}
// Green Address compatibility pattern. Will be removed in the future.
// m / 3' / [1-100]' / [1,4] / address_index
if (address_n_count > 0 && address_n[0] == (0x80000000 + 3)) {
if (address_n[0] == PATH_HARDENED + 3) {
valid = valid && (coin->coin_type == SLIP44_BITCOIN);
if (check_known) {
valid = valid && (address_n_count == 4);
valid = valid && ((address_n[1] & 0x80000000) == 0x80000000);
valid = valid && ((address_n[1] & 0x7fffffff) <= 100);
valid = valid && (address_n[2] == 1 || address_n[2] == 4);
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
valid = valid && (address_n_count == 4);
valid = valid && (address_n[1] & PATH_HARDENED);
valid = valid && ((address_n[1] & PATH_UNHARDEN_MASK) <= 100);
valid = valid && (address_n[2] == 1 || address_n[2] == 4);
valid = valid && (address_n[3] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && (script_type != InputScriptType_SPENDTAPROOT);
}
return valid;
}
@ -723,41 +692,36 @@ bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
// Green Address compatibility patterns. Will be removed in the future.
// m / 1195487518
// m / 1195487518 / 6 / address_index
if (address_n_count > 0 && address_n[0] == 1195487518) {
if (address_n[0] == 1195487518) {
valid = valid && (coin->coin_type == SLIP44_BITCOIN);
if (check_known) {
if (address_n_count == 3) {
valid = valid && (address_n[1] == 6);
valid = valid && (address_n[2] <= PATH_MAX_ADDRESS_INDEX);
} else if (address_n_count != 1) {
return false;
}
if (address_n_count == 3) {
valid = valid && (address_n[1] == 6);
valid = valid && (address_n[2] <= PATH_MAX_ADDRESS_INDEX);
} else if (address_n_count != 1) {
return false;
}
if (full_check) {
return false;
}
return valid;
}
// Casa compatibility pattern. Will be removed in the future.
// m / 49 / coin_type / account / change / address_index
if (address_n_count > 0 && address_n[0] == 49) {
if (check_known) {
valid = valid && (address_n_count == 5);
} else {
valid = valid && (address_n_count >= 2);
}
if (address_n[0] == 49) {
valid = valid && (address_n_count == 5);
valid =
valid && check_cointype(coin, 0x80000000 | address_n[1], check_known);
if (check_script_type) {
valid && check_cointype(coin, PATH_HARDENED | address_n[1], full_check);
valid = valid && ((address_n[1] & PATH_HARDENED) == 0);
valid = valid && (address_n[2] <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
if (full_check) {
valid = valid && (script_type == InputScriptType_SPENDP2SHWITNESS);
}
if (check_known) {
valid = valid && ((address_n[1] & 0x80000000) == 0);
valid = valid && (address_n[2] <= PATH_MAX_ACCOUNT);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
}
return valid;
}
// we allow unknown paths only when a full check is not required
return level == CoinPathCheckLevel_BASIC;
// unknown path
return false;
}

@ -32,11 +32,11 @@
#include "messages-bitcoin.pb.h"
#include "messages-crypto.pb.h"
typedef enum _CoinPathCheckLevel {
CoinPathCheckLevel_BASIC = 0,
CoinPathCheckLevel_KNOWN = 1,
CoinPathCheckLevel_SCRIPT_TYPE = 2,
} CoinPathCheckLevel;
#define PATH_HARDENED 0x80000000
#define PATH_UNHARDEN_MASK 0x7fffffff
#define PATH_MAX_ACCOUNT 100
#define PATH_MAX_CHANGE 1
#define PATH_MAX_ADDRESS_INDEX 1000000
#define ser_length_size(len) ((len) < 253 ? 1 : (len) < 0x10000 ? 3 : 5)
@ -79,6 +79,6 @@ int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash);
bool coin_path_check(const CoinInfo *coin, InputScriptType script_type,
uint32_t address_n_count, const uint32_t *address_n,
bool has_multisig, CoinPathCheckLevel level);
bool has_multisig, bool full_check);
#endif

@ -1040,3 +1040,52 @@ bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) {
}
return true;
}
bool ethereum_path_check(uint32_t address_n_count, const uint32_t *address_n,
bool pubkey_export, uint64_t chain) {
bool valid = (address_n_count >= 3);
valid = valid && (address_n[0] == (PATH_HARDENED | 44));
valid = valid && (address_n[1] & PATH_HARDENED);
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
uint32_t path_slip44 = address_n[1] & PATH_UNHARDEN_MASK;
if (chain == CHAIN_ID_UNKNOWN) {
valid = valid && (is_ethereum_slip44(path_slip44));
} else {
uint32_t chain_slip44 = ethereum_slip44_by_chain_id(chain);
if (chain_slip44 == SLIP44_UNKNOWN) {
// Allow Ethereum or testnet paths for unknown networks.
valid = valid && (path_slip44 == 60 || path_slip44 == 1);
} else if (chain_slip44 != 60 && chain_slip44 != 1) {
// Allow cross-signing with Ethereum unless it's testnet.
valid = valid && (path_slip44 == chain_slip44 || path_slip44 == 60);
} else {
valid = valid && (path_slip44 == chain_slip44);
}
}
if (pubkey_export) {
// m/44'/coin_type'/account'/*
return valid;
}
if (address_n_count == 3) {
// SEP-0005 for non-UTXO-based currencies, defined by Stellar:
// https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md
// m/44'/coin_type'/account'
return valid;
}
// We believe Ethereum should use the SEP-0005 scheme for everything, because
// it is account-based, rather than UTXO-based. Unfortunately, a lot of
// Ethereum tools (MEW, Metamask) do not use such scheme and set account = 0
// and then iterate the address index. For compatibility, we allow this scheme
// as well.
// m/44'/coin_type'/account'/change/address_index
valid = valid && (address_n_count == 5);
valid = valid && (address_n[3] <= PATH_MAX_CHANGE);
valid = valid && (address_n[4] <= PATH_MAX_ADDRESS_INDEX);
return valid;
}

@ -25,6 +25,8 @@
#include "bip32.h"
#include "messages-ethereum.pb.h"
#define CHAIN_ID_UNKNOWN UINT64_MAX
void ethereum_signing_init(const EthereumSignTx *msg, const HDNode *node);
void ethereum_signing_init_eip1559(const EthereumSignTxEIP1559 *msg,
const HDNode *node);
@ -39,4 +41,6 @@ void ethereum_typed_hash_sign(const EthereumSignTypedHash *msg,
EthereumTypedDataSignature *resp);
bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]);
bool ethereum_path_check(uint32_t address_n_count, const uint32_t *address_n,
bool pubkey_export, uint64_t chain);
#endif

@ -3,14 +3,19 @@ BKSL = "\\"
networks = list(supported_on("trezor1", eth))
max_chain_id_length = 0
max_slip44_length = 0
max_suffix_length = 0
for n in networks:
max_chain_id_length = max(len(str(n.chain_id)), max_chain_id_length)
max_slip44_length = max(len(str(n.slip44)), max_slip44_length)
max_suffix_length = max(len(n.shortcut), max_suffix_length)
def align_chain_id(n):
return "{:>{w}}".format(n.chain_id, w=max_chain_id_length)
def align_slip44(n):
return "{:>{w}}".format(n.slip44, w=max_slip44_length)
def align_suffix(n):
cstr = c_str(" " + n.shortcut) + ";"
# we add two quotes, a space and a semicolon. hence +4 chars
@ -23,12 +28,34 @@ def align_suffix(n):
#ifndef __ETHEREUM_NETWORKS_H__
#define __ETHEREUM_NETWORKS_H__
#define SLIP44_UNKNOWN UINT32_MAX
#define ASSIGN_ETHEREUM_SUFFIX(suffix, chain_id) ${BKSL}
switch (chain_id) { ${BKSL}
switch (chain_id) { ${BKSL}
% for n in networks:
case ${align_chain_id(n)}: suffix = ${align_suffix(n)} break; /* ${n.name} */ ${BKSL}
% endfor
default: suffix = " UNKN"; break; /* unknown chain */ ${BKSL}
}
static bool is_ethereum_slip44(uint32_t slip44) {
switch (slip44) {
% for slip44 in sorted(set(n.slip44 for n in networks)):
case ${slip44}:
% endfor
return true;
default:
return false;
}
}
static int32_t ethereum_slip44_by_chain_id(uint64_t chain_id) {
switch (chain_id) {
% for n in networks:
case ${align_chain_id(n)}: suffix = ${align_suffix(n)} break; /* ${n.name} */ ${BKSL}
case ${align_chain_id(n)}: return ${align_slip44(n)}; /* ${n.name} */
% endfor
default: suffix = " UNKN"; break; /* unknown chain */ ${BKSL}
}
default: return SLIP44_UNKNOWN; /* unknown chain */
}
}
#endif

@ -100,6 +100,12 @@ static uint8_t msg_resp[MSG_OUT_DECODED_SIZE] __attribute__((aligned));
return; \
}
#define CHECK_UNLOCKED \
if (!session_isUnlocked()) { \
layoutHome(); \
return; \
}
#define CHECK_PARAM(cond, errormsg) \
if (!(cond)) { \
fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \
@ -370,6 +376,27 @@ void fsm_msgRebootToBootloader(void) {
#endif
}
void fsm_abortWorkflows(void) {
recovery_abort();
signing_abort();
#if !BITCOIN_ONLY
ethereum_signing_abort();
stellar_signingAbort();
#endif
}
bool fsm_layoutPathWarning(void) {
layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL,
_("Wrong address path"), _("for selected coin."), NULL,
_("Continue at your"), _("own risk!"), NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_UnknownDerivationPath,
false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
return false;
}
return true;
}
#include "fsm_msg_coin.h"
#include "fsm_msg_common.h"
#include "fsm_msg_crypto.h"

@ -20,6 +20,7 @@
#ifndef __FSM_H__
#define __FSM_H__
#include "coins.h"
#include "messages-bitcoin.pb.h"
#include "messages-crypto.pb.h"
#include "messages-debug.pb.h"
@ -143,4 +144,11 @@ void fsm_msgRebootToBootloader(void);
bool fsm_layoutSignMessage(const uint8_t *msg, uint32_t len);
bool fsm_layoutVerifyMessage(const uint8_t *msg, uint32_t len);
bool fsm_layoutPathWarning(void);
bool fsm_checkCoinPath(const CoinInfo *coin, InputScriptType script_type,
uint32_t address_n_count, const uint32_t *address_n,
bool has_multisig, bool show_warning);
void fsm_abortWorkflows(void);
#endif

@ -37,7 +37,7 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) {
// derive m/0' to obtain root_fingerprint
uint32_t root_fingerprint;
uint32_t path[1] = {0x80000000 | 0};
uint32_t path[1] = {PATH_HARDENED | 0};
HDNode *node = fsm_getDerivedNode(curve, path, 1, &root_fingerprint);
if (!node) return;
@ -146,34 +146,32 @@ void fsm_msgSignTx(const SignTx *msg) {
}
void fsm_msgTxAck(TxAck *msg) {
CHECK_UNLOCKED
CHECK_PARAM(msg->has_tx, _("No transaction provided"));
signing_txack(&(msg->tx));
}
static bool fsm_checkCoinPath(const CoinInfo *coin, InputScriptType script_type,
uint32_t address_n_count,
const uint32_t *address_n, bool has_multisig) {
if (!coin_path_check(coin, script_type, address_n_count, address_n,
has_multisig, CoinPathCheckLevel_SCRIPT_TYPE)) {
if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict &&
!coin_path_check(coin, script_type, address_n_count, address_n,
has_multisig, CoinPathCheckLevel_KNOWN)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path"));
layoutHome();
return false;
}
bool fsm_checkCoinPath(const CoinInfo *coin, InputScriptType script_type,
uint32_t address_n_count, const uint32_t *address_n,
bool has_multisig, bool show_warning) {
if (coin_path_check(coin, script_type, address_n_count, address_n,
has_multisig, true)) {
return true;
}
layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL,
_("Wrong address path"), _("for selected coin."), NULL,
_("Continue at your"), _("own risk!"), NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_UnknownDerivationPath,
false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return false;
}
if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict &&
!coin_path_check(coin, script_type, address_n_count, address_n,
has_multisig, false)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path"));
return false;
}
if (show_warning) {
return fsm_layoutPathWarning();
}
return true;
}
@ -186,6 +184,14 @@ void fsm_msgGetAddress(const GetAddress *msg) {
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return;
if (!fsm_checkCoinPath(coin, msg->script_type, msg->address_n_count,
msg->address_n, msg->has_multisig,
msg->show_display)) {
layoutHome();
return;
}
HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
@ -225,11 +231,6 @@ void fsm_msgGetAddress(const GetAddress *msg) {
strlcpy(desc, _("Address:"), sizeof(desc));
}
if (!fsm_checkCoinPath(coin, msg->script_type, msg->address_n_count,
msg->address_n, msg->has_multisig)) {
return;
}
uint32_t multisig_xpub_magic = coin->xpub_magic;
if (msg->has_multisig && coin->has_segwit) {
if (!msg->has_ignore_xpub_magic || !msg->ignore_xpub_magic) {
@ -274,7 +275,8 @@ void fsm_msgSignMessage(const SignMessage *msg) {
if (!coin) return;
if (!fsm_checkCoinPath(coin, msg->script_type, msg->address_n_count,
msg->address_n, false)) {
msg->address_n, false, true)) {
layoutHome();
return;
}

@ -95,8 +95,7 @@ bool get_features(Features *resp) {
}
void fsm_msgInitialize(const Initialize *msg) {
recovery_abort();
signing_abort();
fsm_abortWorkflows();
uint8_t *session_id;
if (msg && msg->has_session_id) {
@ -251,6 +250,8 @@ void fsm_msgWipeDevice(const WipeDevice *msg) {
}
void fsm_msgGetEntropy(const GetEntropy *msg) {
CHECK_PIN
#if !DEBUG_RNG
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("send entropy?"), NULL, NULL,
@ -345,11 +346,7 @@ void fsm_msgBackupDevice(const BackupDevice *msg) {
void fsm_msgCancel(const Cancel *msg) {
(void)msg;
recovery_abort();
signing_abort();
#if !BITCOIN_ONLY
ethereum_signing_abort();
#endif
fsm_abortWorkflows();
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
}
@ -516,9 +513,15 @@ void fsm_msgRecoveryDevice(const RecoveryDevice *msg) {
msg->has_u2f_counter ? msg->u2f_counter : 0, dry_run);
}
void fsm_msgWordAck(const WordAck *msg) { recovery_word(msg->word); }
void fsm_msgWordAck(const WordAck *msg) {
CHECK_UNLOCKED
recovery_word(msg->word);
}
void fsm_msgSetU2FCounter(const SetU2FCounter *msg) {
CHECK_PIN
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you want to set"), _("the U2F counter?"), NULL, NULL,
NULL, NULL);
@ -533,6 +536,8 @@ void fsm_msgSetU2FCounter(const SetU2FCounter *msg) {
}
void fsm_msgGetNextU2FCounter() {
CHECK_PIN
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you want to"), _("increase and retrieve"),
_("the U2F counter?"), NULL, NULL, NULL);

@ -75,6 +75,8 @@ void fsm_msgSignIdentity(const SignIdentity *msg) {
CHECK_INITIALIZED
CHECK_PIN
layoutSignIdentity(&(msg->identity),
msg->has_challenge_visual ? msg->challenge_visual : 0);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
@ -83,8 +85,6 @@ void fsm_msgSignIdentity(const SignIdentity *msg) {
return;
}
CHECK_PIN
uint8_t hash[32];
if (cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity"));
@ -93,14 +93,14 @@ void fsm_msgSignIdentity(const SignIdentity *msg) {
}
uint32_t address_n[5];
address_n[0] = 0x80000000 | 13;
address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
address_n[0] = PATH_HARDENED | 13;
address_n[1] = PATH_HARDENED | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
((uint32_t)hash[3] << 24);
address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
address_n[2] = PATH_HARDENED | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
((uint32_t)hash[7] << 24);
address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
address_n[3] = PATH_HARDENED | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
((uint32_t)hash[11] << 24);
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
address_n[4] = PATH_HARDENED | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
((uint32_t)hash[15] << 24);
const char *curve = SECP256K1_NAME;
@ -179,6 +179,8 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
CHECK_INITIALIZED
CHECK_PIN
layoutDecryptIdentity(&msg->identity);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
@ -186,8 +188,6 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
return;
}
CHECK_PIN
uint8_t hash[32];
if (cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity"));
@ -196,14 +196,14 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
}
uint32_t address_n[5];
address_n[0] = 0x80000000 | 17;
address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
address_n[0] = PATH_HARDENED | 17;
address_n[1] = PATH_HARDENED | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
((uint32_t)hash[3] << 24);
address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
address_n[2] = PATH_HARDENED | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
((uint32_t)hash[7] << 24);
address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
address_n[3] = PATH_HARDENED | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
((uint32_t)hash[11] << 24);
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
address_n[4] = PATH_HARDENED | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
((uint32_t)hash[15] << 24);
const char *curve = SECP256K1_NAME;
@ -235,6 +235,22 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
layoutHome();
}
static bool fsm_checkCosiPath(uint32_t address_n_count,
const uint32_t *address_n) {
// The path should typically match "m / 10018' / [0-9]'", but we allow
// any path from the SLIP-18 domain "m / 10018' / *".
if (address_n_count >= 1 && address_n[0] == PATH_HARDENED + 10018) {
return true;
}
if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict) {
fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path"));
return false;
}
return fsm_layoutPathWarning();
}
void fsm_msgCosiCommit(const CosiCommit *msg) {
RESP_INIT(CosiCommitment);
@ -242,6 +258,13 @@ void fsm_msgCosiCommit(const CosiCommit *msg) {
CHECK_PARAM(msg->has_data, _("No data provided"));
CHECK_PIN
if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) {
layoutHome();
return;
}
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
msg->data.size, false);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
@ -250,8 +273,6 @@ void fsm_msgCosiCommit(const CosiCommit *msg) {
return;
}
CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
@ -285,6 +306,13 @@ void fsm_msgCosiSign(const CosiSign *msg) {
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32,
_("Invalid global pubkey"));
if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) {
layoutHome();
return;
}
CHECK_PIN
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
msg->data.size, true);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
@ -293,8 +321,6 @@ void fsm_msgCosiSign(const CosiSign *msg) {
return;
}
CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;

@ -17,6 +17,22 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
static bool fsm_ethereumCheckPath(uint32_t address_n_count,
const uint32_t *address_n, bool pubkey_export,
uint64_t chain_id) {
if (ethereum_path_check(address_n_count, address_n, pubkey_export,
chain_id)) {
return true;
}
if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict) {
fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path"));
return false;
}
return fsm_layoutPathWarning();
}
void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) {
RESP_INIT(EthereumPublicKey);
@ -28,6 +44,12 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) {
const CoinInfo *coin = fsm_getCoin(true, "Bitcoin");
if (!coin) return;
if (!fsm_ethereumCheckPath(msg->address_n_count, msg->address_n, true,
CHAIN_ID_UNKNOWN)) {
layoutHome();
return;
}
const char *curve = coin->curve_name;
uint32_t fingerprint;
HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count,
@ -71,6 +93,12 @@ void fsm_msgEthereumSignTx(const EthereumSignTx *msg) {
CHECK_PIN
if (!fsm_ethereumCheckPath(msg->address_n_count, msg->address_n, false,
msg->chain_id)) {
layoutHome();
return;
}
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
@ -83,6 +111,12 @@ void fsm_msgEthereumSignTxEIP1559(const EthereumSignTxEIP1559 *msg) {
CHECK_PIN
if (!fsm_ethereumCheckPath(msg->address_n_count, msg->address_n, false,
msg->chain_id)) {
layoutHome();
return;
}
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
@ -91,6 +125,8 @@ void fsm_msgEthereumSignTxEIP1559(const EthereumSignTxEIP1559 *msg) {
}
void fsm_msgEthereumTxAck(const EthereumTxAck *msg) {
CHECK_UNLOCKED
ethereum_signing_txack(msg);
}
@ -101,16 +137,25 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) {
CHECK_PIN
if (!fsm_ethereumCheckPath(msg->address_n_count, msg->address_n, false,
CHAIN_ID_UNKNOWN)) {
layoutHome();
return;
}
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
uint8_t pubkeyhash[20];
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) return;
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) {
layoutHome();
return;
}
uint32_t slip44 =
(msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0;
(msg->address_n_count > 1) ? (msg->address_n[1] & PATH_UNHARDEN_MASK) : 0;
bool rskip60 = false;
uint64_t chain_id = 0;
// constants from trezor-common/defs/ethereum/networks.json
@ -150,12 +195,19 @@ void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) {
CHECK_PIN
if (!fsm_ethereumCheckPath(msg->address_n_count, msg->address_n, false,
CHAIN_ID_UNKNOWN)) {
layoutHome();
return;
}
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
uint8_t pubkeyhash[20] = {0};
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) {
layoutHome();
return;
}
@ -230,6 +282,12 @@ void fsm_msgEthereumSignTypedHash(const EthereumSignTypedHash *msg) {
return;
}
if (!fsm_ethereumCheckPath(msg->address_n_count, msg->address_n, false,
CHAIN_ID_UNKNOWN)) {
layoutHome();
return;
}
layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL,
_("Unable to show"), _("EIP-712 data."), NULL,
_("Sign at your own risk."), NULL, NULL);
@ -245,6 +303,7 @@ void fsm_msgEthereumSignTypedHash(const EthereumSignTypedHash *msg) {
uint8_t pubkeyhash[20] = {0};
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) {
layoutHome();
return;
}

@ -17,6 +17,21 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
static bool fsm_nemCheckPath(uint32_t address_n_count,
const uint32_t *address_n, uint8_t network) {
if (nem_path_check(address_n_count, address_n, network, true)) {
return true;
}
if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict &&
!nem_path_check(address_n_count, address_n, network, false)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path"));
return false;
}
return fsm_layoutPathWarning();
}
void fsm_msgNEMGetAddress(NEMGetAddress *msg) {
if (!msg->has_network) {
msg->network = NEM_NETWORK_MAINNET;
@ -31,11 +46,19 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) {
RESP_INIT(NEMAddress);
if (!fsm_nemCheckPath(msg->address_n_count, msg->address_n, msg->network)) {
layoutHome();
return;
}
HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;
if (!hdnode_get_nem_address(node, msg->network, resp->address)) return;
if (!hdnode_get_nem_address(node, msg->network, resp->address)) {
layoutHome();
return;
}
if (msg->has_show_display && msg->show_display) {
char desc[16];
@ -116,6 +139,12 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
RESP_INIT(NEMSignedTx);
if (!fsm_nemCheckPath(msg->transaction.address_n_count,
msg->transaction.address_n, msg->transaction.network)) {
layoutHome();
return;
}
HDNode *node =
fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n,
msg->transaction.address_n_count, NULL);
@ -304,6 +333,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) {
CHECK_PARAM(msg->has_public_key, _("No public key provided"));
CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key"));
CHECK_PIN
char address[NEM_ADDRESS_SIZE + 1];
nem_get_address(msg->public_key.bytes, msg->network, address);
@ -315,8 +346,10 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) {
return;
}
CHECK_PIN
if (!fsm_nemCheckPath(msg->address_n_count, msg->address_n, msg->network)) {
layoutHome();
return;
}
const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return;

@ -17,6 +17,20 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
static bool fsm_stellarCheckPath(uint32_t address_n_count,
const uint32_t *address_n) {
if (stellar_path_check(address_n_count, address_n)) {
return true;
}
if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict) {
fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path"));
return false;
}
return fsm_layoutPathWarning();
}
void fsm_msgStellarGetAddress(const StellarGetAddress *msg) {
RESP_INIT(StellarAddress);
@ -24,10 +38,16 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg) {
CHECK_PIN
if (!fsm_stellarCheckPath(msg->address_n_count, msg->address_n)) {
layoutHome();
return;
}
const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count);
if (!node) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
layoutHome();
return;
}
@ -55,6 +75,11 @@ void fsm_msgStellarSignTx(const StellarSignTx *msg) {
CHECK_INITIALIZED
CHECK_PIN
if (!fsm_stellarCheckPath(msg->address_n_count, msg->address_n)) {
layoutHome();
return;
}
if (!stellar_signingInit(msg)) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
@ -72,6 +97,8 @@ void fsm_msgStellarSignTx(const StellarSignTx *msg) {
}
void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmCreateAccountOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -90,6 +117,8 @@ void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) {
}
void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) {
CHECK_UNLOCKED
// This will display additional dialogs to the user
if (!stellar_confirmPaymentOp(msg)) return;
@ -111,6 +140,8 @@ void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) {
void fsm_msgStellarPathPaymentStrictReceiveOp(
const StellarPathPaymentStrictReceiveOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmPathPaymentStrictReceiveOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -130,6 +161,8 @@ void fsm_msgStellarPathPaymentStrictReceiveOp(
void fsm_msgStellarPathPaymentStrictSendOp(
const StellarPathPaymentStrictSendOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmPathPaymentStrictSendOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -148,6 +181,8 @@ void fsm_msgStellarPathPaymentStrictSendOp(
}
void fsm_msgStellarManageBuyOfferOp(const StellarManageBuyOfferOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmManageBuyOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -166,6 +201,8 @@ void fsm_msgStellarManageBuyOfferOp(const StellarManageBuyOfferOp *msg) {
}
void fsm_msgStellarManageSellOfferOp(const StellarManageSellOfferOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmManageSellOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -185,6 +222,8 @@ void fsm_msgStellarManageSellOfferOp(const StellarManageSellOfferOp *msg) {
void fsm_msgStellarCreatePassiveSellOfferOp(
const StellarCreatePassiveSellOfferOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmCreatePassiveSellOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -203,6 +242,8 @@ void fsm_msgStellarCreatePassiveSellOfferOp(
}
void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmSetOptionsOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -221,6 +262,8 @@ void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) {
}
void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmChangeTrustOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -239,6 +282,8 @@ void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) {
}
void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmAllowTrustOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -257,6 +302,8 @@ void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) {
}
void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmAccountMergeOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -275,6 +322,8 @@ void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) {
}
void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmManageDataOp(msg)) return;
if (stellar_allOperationsConfirmed()) {
@ -293,6 +342,8 @@ void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) {
}
void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) {
CHECK_UNLOCKED
if (!stellar_confirmBumpSequenceOp(msg)) return;
if (stellar_allOperationsConfirmed()) {

@ -27,6 +27,7 @@
#include "bignum.h"
#include "bitmaps.h"
#include "config.h"
#include "crypto.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
@ -43,10 +44,10 @@
#if !BITCOIN_ONLY
static const char *slip44_extras(uint32_t coin_type) {
if ((coin_type & 0x80000000) == 0) {
if ((coin_type & PATH_HARDENED) == 0) {
return 0;
}
switch (coin_type & 0x7fffffff) {
switch (coin_type & PATH_UNHARDEN_MASK) {
case 40:
return "EXP"; // Expanse
case 43:
@ -82,14 +83,15 @@ static const char *address_n_str(const uint32_t *address_n,
// known BIP44/49/84/86 path
static char path[100];
if (address_n_count == 5 &&
(address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) ||
address_n[0] == (0x80000000 + 84) ||
address_n[0] == (0x80000000 + 86)) &&
(address_n[1] & 0x80000000) && (address_n[2] & 0x80000000) &&
(address_n[0] == (PATH_HARDENED + 44) ||
address_n[0] == (PATH_HARDENED + 49) ||
address_n[0] == (PATH_HARDENED + 84) ||
address_n[0] == (PATH_HARDENED + 86)) &&
(address_n[1] & PATH_HARDENED) && (address_n[2] & PATH_HARDENED) &&
(address_n[3] <= 1) && (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) {
bool taproot = (address_n[0] == (0x80000000 + 86));
bool native_segwit = (address_n[0] == (0x80000000 + 84));
bool p2sh_segwit = (address_n[0] == (0x80000000 + 49));
bool taproot = (address_n[0] == (PATH_HARDENED + 86));
bool native_segwit = (address_n[0] == (PATH_HARDENED + 84));
bool p2sh_segwit = (address_n[0] == (PATH_HARDENED + 49));
bool legacy = false;
const CoinInfo *coin = coinBySlip44(address_n[1]);
const char *abbr = 0;
@ -118,8 +120,8 @@ static const char *address_n_str(const uint32_t *address_n,
}
}
const uint32_t accnum = address_is_account
? ((address_n[4] & 0x7fffffff) + 1)
: (address_n[2] & 0x7fffffff) + 1;
? ((address_n[4] & PATH_UNHARDEN_MASK) + 1)
: (address_n[2] & PATH_UNHARDEN_MASK) + 1;
if (abbr && accnum < 100) {
memzero(path, sizeof(path));
strlcpy(path, abbr, sizeof(path));
@ -164,11 +166,11 @@ static const char *address_n_str(const uint32_t *address_n,
for (int n = (int)address_n_count - 1; n >= 0; n--) {
uint32_t i = address_n[n];
if (i & 0x80000000) {
if (i & PATH_HARDENED) {
*c = '\'';
c--;
}
i = i & 0x7fffffff;
i = i & PATH_UNHARDEN_MASK;
do {
*c = '0' + (i % 10);
c--;
@ -596,6 +598,13 @@ void layoutChangeCountOverThreshold(uint32_t change_count) {
_("Continue?"), NULL);
}
void layoutConfirmUnverifiedExternalInputs(void) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Warning!"), _("The transaction"),
_("contains unverified"), _("external inputs."),
_("Continue?"), NULL);
}
void layoutConfirmNondefaultLockTime(uint32_t lock_time,
bool lock_time_disabled) {
if (lock_time_disabled) {
@ -1176,8 +1185,10 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) {
static inline bool is_slip18(const uint32_t *address_n,
size_t address_n_count) {
return address_n_count == 2 && address_n[0] == (0x80000000 + 10018) &&
(address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9;
// m / 10018' / [0-9]'
return address_n_count == 2 && address_n[0] == (PATH_HARDENED + 10018) &&
(address_n[1] & PATH_HARDENED) &&
(address_n[1] & PATH_UNHARDEN_MASK) <= 9;
}
void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count,
@ -1187,10 +1198,10 @@ void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count,
if (is_slip18(address_n, address_n_count)) {
if (final_sign) {
strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf));
desc_buf[16] = '0' + (address_n[1] & 0x7FFFFFFF);
desc_buf[16] = '0' + (address_n[1] & PATH_UNHARDEN_MASK);
} else {
strlcpy(desc_buf, _("CoSi commit index #?"), sizeof(desc_buf));
desc_buf[18] = '0' + (address_n[1] & 0x7FFFFFFF);
desc_buf[18] = '0' + (address_n[1] & PATH_UNHARDEN_MASK);
}
desc = desc_buf;
}

@ -68,6 +68,7 @@ void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t fee);
void layoutChangeCountOverThreshold(uint32_t change_count);
void layoutConfirmUnverifiedExternalInputs(void);
void layoutConfirmNondefaultLockTime(uint32_t lock_time,
bool lock_time_disabled);
void layoutVerifyAddress(const CoinInfo *coin, const char *address);

@ -20,6 +20,7 @@
#include "nem2.h"
#include "aes/aes.h"
#include "crypto.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
@ -741,3 +742,44 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition,
return false;
}
}
bool nem_path_check(uint32_t address_n_count, const uint32_t *address_n,
uint8_t network, bool check_coin_type) {
bool valid = (address_n_count >= 3);
valid = valid && (address_n[0] == (PATH_HARDENED | 44));
valid = valid && (address_n[1] == (PATH_HARDENED | 43) ||
address_n[1] == (PATH_HARDENED | 1));
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
if (address_n_count == 3) {
// SEP-0005 for non-UTXO-based currencies, defined by Stellar:
// https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md
// m/44'/coin_type'/account'
// No further checks required.
} else if (address_n_count == 5) {
// NanoWallet compatibility path
// "m/44'/coin_type'/account'/0'/0'"
valid = valid && (address_n[3] == (PATH_HARDENED | 0));
valid = valid && (address_n[4] == (PATH_HARDENED | 0));
} else {
return false;
}
if (check_coin_type) {
// Check that the appropriate coin_type is set for the given network.
switch (network) {
case NEM_NETWORK_MAINNET:
case NEM_NETWORK_MIJIN:
valid = valid && (address_n[1] == (PATH_HARDENED | 43));
break;
case NEM_NETWORK_TESTNET:
valid = valid && (address_n[1] == (PATH_HARDENED | 1));
break;
default:
return false;
}
}
return valid;
}

@ -100,6 +100,9 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
uint8_t network, char *str_out, size_t size);
bool nem_path_check(uint32_t address_n_count, const uint32_t *address_n,
uint8_t network, bool check_coin_type);
static inline void nem_mosaicFormatName(const char *namespace,
const char *mosaic, char *str_out,
size_t size) {

File diff suppressed because it is too large Load Diff

@ -155,6 +155,22 @@ bool stellar_signingInit(const StellarSignTx *msg) {
return true;
}
void stellar_signingAbort(void) {
if (stellar_signing) {
stellar_signing = false;
layoutHome();
}
}
static void stellar_signingFail(const char *reason) {
if (!reason) {
reason = _("Unknown error");
}
fsm_sendFailure(FailureType_Failure_ProcessError, reason);
stellar_signingAbort();
}
bool stellar_confirmSourceAccount(bool has_source_account,
const char *str_account) {
stellar_hashupdate_bool(has_source_account);
@ -174,7 +190,7 @@ bool stellar_confirmSourceAccount(bool has_source_account,
str_addr_rows[0], str_addr_rows[1],
str_addr_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -189,7 +205,7 @@ bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -199,7 +215,7 @@ bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) {
// Validate new account and convert to bytes
uint8_t new_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->new_account, new_account_bytes)) {
stellar_signingAbort(_("Invalid new account address"));
stellar_signingFail(_("Invalid new account address"));
return false;
}
@ -218,7 +234,7 @@ bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) {
str_addr_rows[1], str_addr_rows[2],
str_amount_line);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -236,7 +252,7 @@ bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -247,7 +263,7 @@ bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) {
uint8_t destination_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->destination_account,
destination_account_bytes)) {
stellar_signingAbort(_("Invalid destination account"));
stellar_signingFail(_("Invalid destination account"));
return false;
}
@ -273,7 +289,7 @@ bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) {
stellar_layoutTransactionDialog(str_pay_amount, str_asset_row, str_to,
str_addr_rows[1], str_addr_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -295,7 +311,7 @@ bool stellar_confirmPathPaymentStrictReceiveOp(
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -306,7 +322,7 @@ bool stellar_confirmPathPaymentStrictReceiveOp(
uint8_t destination_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->destination_account,
destination_account_bytes)) {
stellar_signingAbort(_("Invalid destination account"));
stellar_signingFail(_("Invalid destination account"));
return false;
}
const char **str_dest_rows =
@ -343,7 +359,7 @@ bool stellar_confirmPathPaymentStrictReceiveOp(
stellar_layoutTransactionDialog(str_pay_amount, str_dest_asset, str_to,
str_dest_rows[1], str_dest_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -360,7 +376,7 @@ bool stellar_confirmPathPaymentStrictReceiveOp(
_("This is the max"),
_("amount debited from your"), _("account."));
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
// Note: no confirmation for intermediate steps since they don't impact the
@ -394,7 +410,7 @@ bool stellar_confirmPathPaymentStrictSendOp(
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -405,7 +421,7 @@ bool stellar_confirmPathPaymentStrictSendOp(
uint8_t destination_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->destination_account,
destination_account_bytes)) {
stellar_signingAbort(_("Invalid destination account"));
stellar_signingFail(_("Invalid destination account"));
return false;
}
const char **str_dest_rows =
@ -441,7 +457,7 @@ bool stellar_confirmPathPaymentStrictSendOp(
stellar_layoutTransactionDialog(_("Path Pay at least"), str_pay_amount,
str_dest_asset, str_to, str_dest_rows[1]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -458,7 +474,7 @@ bool stellar_confirmPathPaymentStrictSendOp(
str_dest_rows[2], str_source_amount, str_send_asset,
_("This is the amount debited"), _("from your account."));
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
// Note: no confirmation for intermediate steps since they don't impact the
@ -491,7 +507,7 @@ bool stellar_confirmManageBuyOfferOp(const StellarManageBuyOfferOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -551,7 +567,7 @@ bool stellar_confirmManageBuyOfferOp(const StellarManageBuyOfferOp *msg) {
stellar_layoutTransactionDialog(str_offer, str_buying, str_buying_asset,
str_selling, str_selling_asset);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -578,7 +594,7 @@ bool stellar_confirmManageSellOfferOp(const StellarManageSellOfferOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -637,7 +653,7 @@ bool stellar_confirmManageSellOfferOp(const StellarManageSellOfferOp *msg) {
stellar_layoutTransactionDialog(str_offer, str_selling, str_selling_asset,
str_buying, str_buying_asset);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -665,7 +681,7 @@ bool stellar_confirmCreatePassiveSellOfferOp(
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -715,7 +731,7 @@ bool stellar_confirmCreatePassiveSellOfferOp(
stellar_layoutTransactionDialog(str_offer, str_selling, str_selling_asset,
str_buying, str_buying_asset);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -740,7 +756,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -762,7 +778,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
uint8_t inflation_destination_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->inflation_destination_account,
inflation_destination_account_bytes)) {
stellar_signingAbort(_("Invalid inflation destination account"));
stellar_signingFail(_("Invalid inflation destination account"));
return false;
}
const char **str_addr_rows =
@ -771,7 +787,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
stellar_layoutTransactionDialog(str_title, NULL, str_addr_rows[0],
str_addr_rows[1], str_addr_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -786,7 +802,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
// Auth required
if (msg->clear_flags > 7) {
stellar_signingAbort(_("Invalid flags"));
stellar_signingFail(_("Invalid flags"));
return false;
}
if (msg->clear_flags & 0x01) {
@ -807,7 +823,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
stellar_layoutTransactionDialog(str_title, rows[0], rows[1], rows[2],
rows[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
memzero(rows, sizeof(rows));
@ -824,7 +840,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
// Auth required
if (msg->set_flags > 7) {
stellar_signingAbort(_("Invalid flags"));
stellar_signingFail(_("Invalid flags"));
return false;
}
if (msg->set_flags & 0x01) {
@ -845,7 +861,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
stellar_layoutTransactionDialog(str_title, rows[0], rows[1], rows[2],
rows[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
memzero(rows, sizeof(rows));
@ -919,7 +935,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
stellar_layoutTransactionDialog(str_title, rows[0], rows[1], rows[2],
rows[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
memzero(rows, sizeof(rows));
@ -942,7 +958,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
stellar_layoutTransactionDialog(str_title, rows[0], rows[1], NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
memzero(rows, sizeof(rows));
@ -982,7 +998,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
str_addr_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall,
false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
break;
@ -998,12 +1014,12 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
_("screen)"));
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall,
false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
break;
default:
stellar_signingAbort(_("Stellar: invalid signer type"));
stellar_signingFail(_("Stellar: invalid signer type"));
return false;
}
@ -1017,7 +1033,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) {
stellar_layoutTransactionDialog(_("Confirm Hash"), rows[0], rows[1],
rows[2], rows[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
memzero(rows, sizeof(rows));
@ -1042,7 +1058,7 @@ bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -1073,7 +1089,7 @@ bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg) {
// Validate destination account and convert to bytes
uint8_t asset_issuer_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->asset.issuer, asset_issuer_bytes)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Invalid asset issuer"));
return false;
@ -1085,7 +1101,7 @@ bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg) {
stellar_layoutTransactionDialog(str_title, str_amount_row, str_addr_rows[0],
str_addr_rows[1], str_addr_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -1104,7 +1120,7 @@ bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -1126,7 +1142,7 @@ bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) {
// Validate account and convert to bytes
uint8_t trusted_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->trusted_account, trusted_account_bytes)) {
stellar_signingAbort(_("Invalid trusted account"));
stellar_signingFail(_("Invalid trusted account"));
return false;
}
@ -1141,7 +1157,7 @@ bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) {
stellar_layoutTransactionDialog(str_title, str_asset_row, str_by,
str_trustor_rows[1], str_trustor_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -1163,7 +1179,7 @@ bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) {
stellar_hashupdate_bytes((uint8_t *)padded_code, 12);
break;
default:
stellar_signingAbort(_("Stellar: invalid asset type"));
stellar_signingFail(_("Stellar: invalid asset type"));
return false;
}
// is authorized
@ -1179,7 +1195,7 @@ bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -1190,7 +1206,7 @@ bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg) {
uint8_t destination_account_bytes[STELLAR_KEY_SIZE] = {0};
if (!stellar_getAddressBytes(msg->destination_account,
destination_account_bytes)) {
stellar_signingAbort(_("Invalid destination account"));
stellar_signingFail(_("Invalid destination account"));
return false;
}
@ -1202,7 +1218,7 @@ bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg) {
str_destination_rows[0], str_destination_rows[1],
str_destination_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -1219,7 +1235,7 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -1240,7 +1256,7 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg) {
stellar_layoutTransactionDialog(str_title, str_key_lines[0], str_key_lines[1],
str_key_lines[2], str_key_lines[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -1258,7 +1274,7 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg) {
str_hash_lines[1], str_hash_lines[2],
str_hash_lines[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
}
@ -1282,7 +1298,7 @@ bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg) {
if (!stellar_confirmSourceAccount(msg->has_source_account,
msg->source_account)) {
stellar_signingAbort(_("Source account error"));
stellar_signingFail(_("Source account error"));
return false;
}
@ -1295,7 +1311,7 @@ bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg) {
stellar_layoutTransactionDialog(_("Bump Sequence"), _("Set sequence to:"),
str_bump_to, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return false;
}
@ -1307,16 +1323,6 @@ bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg) {
return true;
}
void stellar_signingAbort(const char *reason) {
if (!reason) {
reason = _("Unknown error");
}
stellar_signing = false;
fsm_sendFailure(FailureType_Failure_ProcessError, reason);
layoutHome();
}
/**
* Populates the fields of resp with the signature of the active transaction
*/
@ -1480,7 +1486,7 @@ void stellar_format_asset(const StellarAsset *asset, char *str_formatted,
// Validate issuer account for non-native assets
if (asset->type != StellarAssetType_NATIVE &&
!stellar_validateAddress(asset->issuer)) {
stellar_signingAbort(_("Invalid asset issuer"));
stellar_signingFail(_("Invalid asset issuer"));
return;
}
@ -1736,7 +1742,7 @@ void stellar_hashupdate_asset(const StellarAsset *asset) {
uint8_t issuer_bytes[STELLAR_KEY_SIZE] = {0};
if (asset->type != StellarAssetType_NATIVE &&
!stellar_getAddressBytes(asset->issuer, issuer_bytes)) {
stellar_signingAbort(_("Invalid asset issuer"));
stellar_signingFail(_("Invalid asset issuer"));
return;
}
@ -1804,7 +1810,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) {
str_addr_rows[0], str_addr_rows[1],
str_addr_rows[2]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return;
}
@ -1839,7 +1845,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) {
strlcpy(str_lines[0], _("Memo (RETURN)"), sizeof(str_lines[0]));
break;
default:
stellar_signingAbort(_("Stellar invalid memo type"));
stellar_signingFail(_("Stellar invalid memo type"));
return;
}
@ -1853,7 +1859,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) {
stellar_layoutTransactionDialog(str_lines[0], str_lines[1], str_lines[2],
str_lines[3], str_lines[4]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return;
}
@ -1891,7 +1897,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) {
stellar_layoutTransactionDialog(_("Confirm Time Bounds"), str_lines[0],
str_lines[1], str_lines[2], str_lines[3]);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
stellar_signingAbort(_("User canceled"));
stellar_signingFail(_("User canceled"));
return;
}
}
@ -2013,3 +2019,16 @@ void stellar_layoutTransactionDialog(const char *line1, const char *line2,
line1, line2, line3, line4, line5, stellar_activeTx.address_n,
stellar_activeTx.address_n_count, str_warning, false);
}
bool stellar_path_check(uint32_t address_n_count, const uint32_t *address_n) {
// SEP-0005 for non-UTXO-based currencies, defined by Stellar:
// https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md
// m/44'/coin_type'/account'
bool valid = (address_n_count == 3);
valid = valid && (address_n[0] == (PATH_HARDENED | 44));
valid = valid && (address_n[1] == (PATH_HARDENED | 148) ||
address_n[1] == (PATH_HARDENED | 1));
valid = valid && (address_n[2] & PATH_HARDENED);
valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT);
return valid;
}

@ -54,7 +54,7 @@ typedef struct {
// Signing process
bool stellar_signingInit(const StellarSignTx *tx);
void stellar_signingAbort(const char *reason);
void stellar_signingAbort(void);
bool stellar_confirmSourceAccount(bool has_source_account,
const char *str_account);
bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg);
@ -117,4 +117,6 @@ bool stellar_validateAddress(const char *str_address);
bool stellar_getAddressBytes(const char *str_address, uint8_t *out_bytes);
uint16_t stellar_crc16(uint8_t *bytes, uint32_t length);
bool stellar_path_check(uint32_t address_n_count, const uint32_t *address_n);
#endif

@ -556,22 +556,37 @@ uint32_t serialize_script_multisig(const CoinInfo *coin,
}
// tx methods
void tx_input_check_hash(Hasher *hasher, const TxInputType *input) {
hasher_Update(hasher, input->prev_hash.bytes, sizeof(input->prev_hash.bytes));
hasher_Update(hasher, (const uint8_t *)&input->prev_index,
sizeof(input->prev_index));
hasher_Update(hasher, (const uint8_t *)&input->script_type,
sizeof(input->script_type));
bool tx_input_check_hash(Hasher *hasher, const TxInputType *input) {
hasher_Update(hasher, (const uint8_t *)&input->address_n_count,
sizeof(input->address_n_count));
for (int i = 0; i < input->address_n_count; ++i)
hasher_Update(hasher, (const uint8_t *)&input->address_n[i],
sizeof(input->address_n[0]));
hasher_Update(hasher, input->prev_hash.bytes, sizeof(input->prev_hash.bytes));
hasher_Update(hasher, (const uint8_t *)&input->prev_index,
sizeof(input->prev_index));
tx_script_hash(hasher, input->script_sig.size, input->script_sig.bytes);
hasher_Update(hasher, (const uint8_t *)&input->sequence,
sizeof(input->sequence));
hasher_Update(hasher, (const uint8_t *)&input->script_type,
sizeof(input->script_type));
uint8_t multisig_fp[32] = {0};
if (input->has_multisig) {
if (cryptoMultisigFingerprint(&input->multisig, multisig_fp) == 0) {
// Invalid multisig parameters.
return false;
}
}
hasher_Update(hasher, multisig_fp, sizeof(multisig_fp));
hasher_Update(hasher, (const uint8_t *)&input->amount, sizeof(input->amount));
tx_script_hash(hasher, input->witness.size, input->witness.bytes);
hasher_Update(hasher, (const uint8_t *)&input->has_orig_hash,
sizeof(input->has_orig_hash));
hasher_Update(hasher, input->orig_hash.bytes, sizeof(input->orig_hash.bytes));
hasher_Update(hasher, (const uint8_t *)&input->orig_index,
sizeof(input->orig_index));
tx_script_hash(hasher, input->script_pubkey.size, input->script_pubkey.bytes);
return;
return true;
}
uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) {

@ -79,7 +79,7 @@ int compile_output(const CoinInfo *coin, AmountUnit amount_unit,
int fill_input_script_pubkey(const CoinInfo *coin, const HDNode *root,
TxInputType *in);
void tx_input_check_hash(Hasher *hasher, const TxInputType *input);
bool tx_input_check_hash(Hasher *hasher, const TxInputType *input);
uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input);
uint32_t tx_amount_hash(Hasher *hasher, const TxInputType *input);
uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data);

@ -23,6 +23,7 @@
#include "bip32.h"
#include "buttons.h"
#include "config.h"
#include "crypto.h"
#include "curves.h"
#include "debug.h"
#include "gettext.h"
@ -481,7 +482,7 @@ static const HDNode *generateKeyHandle(const uint8_t app_id[],
uint32_t key_path[KEY_PATH_ENTRIES] = {0};
for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) {
// high bit for hardened keys
key_path[i] = 0x80000000 | random32();
key_path[i] = PATH_HARDENED | random32();
}
// First half of keyhandle is key_path
@ -508,7 +509,7 @@ static const HDNode *validateKeyHandle(const uint8_t app_id[],
memcpy(key_path, key_handle, KEY_PATH_LEN);
for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) {
// check high bit for hardened keys
if (!(key_path[i] & 0x80000000)) {
if (!(key_path[i] & PATH_HARDENED)) {
return NULL;
}
}

@ -3,5 +3,5 @@
#define VERSION_PATCH 2
#define FIX_VERSION_MAJOR 1
#define FIX_VERSION_MINOR 10
#define FIX_VERSION_MINOR 11
#define FIX_VERSION_PATCH 0

@ -25,7 +25,7 @@ if TYPE_CHECKING:
from ..client import TrezorClient
from .. import messages
PATH_HELP = "BIP-32 path, e.g. m/44'/0'/0'/0/0"
PATH_HELP = "BIP-32 path, e.g. m/10018'/0'"
@click.group(name="cosi")

@ -174,7 +174,6 @@ def test_attack_path_segwit(client: Client):
)
@pytest.mark.skip_t1(reason="T1 only prevents using paths known to be altcoins")
def test_invalid_path_fail_asap(client: Client):
inp1 = messages.TxInputType(
address_n=parse_path("m/0"),

@ -134,8 +134,9 @@ def test_p2pkh_fee_bump(client: Client):
request_input(0, TXHASH_beafc7),
request_output(0, TXHASH_beafc7),
(tt, request_orig_input(0, TXHASH_50f6f1)),
(tt, request_orig_output(0, TXHASH_50f6f1)),
(tt, request_orig_output(1, TXHASH_50f6f1)),
request_orig_input(0, TXHASH_50f6f1),
request_orig_output(0, TXHASH_50f6f1),
request_orig_output(1, TXHASH_50f6f1),
request_input(0),
request_output(0),
request_output(1),
@ -257,6 +258,8 @@ def test_p2tr_fee_bump(client: Client):
request_output(1),
request_orig_output(1, TXHASH_8e4af7),
messages.ButtonRequest(code=B.SignTx),
request_orig_input(0, TXHASH_8e4af7),
request_orig_input(1, TXHASH_8e4af7),
request_input(0),
request_input(1),
request_output(0),
@ -328,6 +331,7 @@ def test_p2wpkh_finalize(client: Client):
request_output(0, TXHASH_43d273),
request_output(1, TXHASH_43d273),
request_output(2, TXHASH_43d273),
request_orig_input(0, TXHASH_70f987),
request_input(0),
request_output(0),
request_output(1),
@ -464,6 +468,7 @@ def test_p2wpkh_payjoin(
request_input(0, TXHASH_70f987),
request_output(0, TXHASH_70f987),
request_output(1, TXHASH_70f987),
request_orig_input(0, TXHASH_65b768),
request_input(0),
request_input(1),
request_output(0),
@ -538,6 +543,8 @@ def test_p2wpkh_in_p2sh_remove_change(client: Client):
request_meta(TXHASH_efaa41),
request_input(0, TXHASH_efaa41),
request_output(0, TXHASH_efaa41),
request_orig_input(0, TXHASH_334cd7),
request_orig_input(1, TXHASH_334cd7),
request_input(0),
request_input(1),
request_output(0),
@ -618,6 +625,8 @@ def test_p2wpkh_in_p2sh_fee_bump_from_external(client: Client):
request_meta(TXHASH_efaa41),
request_input(0, TXHASH_efaa41),
request_output(0, TXHASH_efaa41),
request_orig_input(0, TXHASH_334cd7),
request_orig_input(1, TXHASH_334cd7),
request_input(0),
request_input(1),
request_output(0),
@ -759,6 +768,10 @@ def test_tx_meld(client: Client):
request_input(1, TXHASH_927784),
request_input(2, TXHASH_927784),
request_output(0, TXHASH_927784),
request_orig_input(0, TXHASH_334cd7),
request_orig_input(1, TXHASH_334cd7),
request_orig_input(0, TXHASH_ed89ac),
request_orig_input(1, TXHASH_ed89ac),
request_input(0),
request_input(1),
request_input(2),

@ -18,6 +18,7 @@ import pytest
from trezorlib import device, messages
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from ...common import MNEMONIC12
@ -84,7 +85,7 @@ def test_pin_passphrase(client: Client):
assert client.features.passphrase_protection is True
# Do passphrase-protected action, PassphraseRequest should be raised
resp = client.call_raw(messages.GetAddress())
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
assert isinstance(resp, messages.PassphraseRequest)
client.call_raw(messages.Cancel())
@ -135,7 +136,7 @@ def test_nopin_nopassphrase(client: Client):
assert client.features.passphrase_protection is False
# Do pin & passphrase-protected action, PassphraseRequest should NOT be raised
resp = client.call_raw(messages.GetAddress())
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
assert isinstance(resp, messages.Address)

@ -19,6 +19,7 @@ from mnemonic import Mnemonic
from trezorlib import device, messages
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from ...common import generate_entropy
@ -87,7 +88,7 @@ def reset_device(client: Client, strength):
assert resp.passphrase_protection is False
# Do pin & passphrase-protected action, PassphraseRequest should NOT be raised
resp = client.call_raw(messages.GetAddress())
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
assert isinstance(resp, messages.Address)
@ -186,7 +187,7 @@ def test_reset_device_256_pin(client: Client):
assert resp.passphrase_protection is True
# Do passphrase-protected action, PassphraseRequest should be raised
resp = client.call_raw(messages.GetAddress())
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
assert isinstance(resp, messages.PassphraseRequest)
client.call_raw(messages.Cancel())

@ -18,8 +18,9 @@ import time
import pytest
from trezorlib import btc
from trezorlib import btc, device
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.messages import SafetyCheckLevel
from trezorlib.tools import H_
pytestmark = [
@ -29,6 +30,8 @@ pytestmark = [
def test_public_ckd(client: Client):
# disable safety checks to access non-standard paths
device.apply_settings(client, safety_checks=SafetyCheckLevel.PromptTemporarily)
btc.get_address(client, "Bitcoin", []) # to compute root node via BIP39
for depth in range(8):
@ -41,6 +44,8 @@ def test_public_ckd(client: Client):
def test_private_ckd(client: Client):
# disable safety checks to access non-standard paths
device.apply_settings(client, safety_checks=SafetyCheckLevel.PromptTemporarily)
btc.get_address(client, "Bitcoin", []) # to compute root node via BIP39
for depth in range(8):
@ -54,6 +59,9 @@ def test_private_ckd(client: Client):
def test_cache(client: Client):
# disable safety checks to access non-standard paths
device.apply_settings(client, safety_checks=SafetyCheckLevel.PromptTemporarily)
start = time.time()
for x in range(10):
btc.get_address(client, "Bitcoin", [x, 2, 3, 4, 5, 6, 7, 8])

@ -18,6 +18,7 @@ import pytest
from trezorlib import debuglink, device, messages, misc
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from trezorlib.transport import udp
from ..common import MNEMONIC12
@ -40,7 +41,7 @@ def test_mnemonic(client: Client):
@pytest.mark.skip_t2
@pytest.mark.setup_client(mnemonic=MNEMONIC12, pin="1234", passphrase="")
def test_pin(client: Client):
resp = client.call_raw(messages.GetAddress())
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
assert isinstance(resp, messages.PinMatrixRequest)
state = client.debug.state()

@ -19,6 +19,7 @@ import pytest
from trezorlib import device, exceptions, messages
from trezorlib.client import MAX_PIN_LENGTH
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
PinType = messages.PinMatrixRequestType
@ -177,7 +178,7 @@ def test_set_pin_to_wipe_code(client: Client):
# Check that there is no PIN protection.
client.init_device()
assert client.features.pin_protection is False
resp = client.call_raw(messages.GetAddress())
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
assert isinstance(resp, messages.Address)

@ -158,21 +158,7 @@ def test_ping(client: Client):
client.ping("msg", True)
@pytest.mark.skip_t2
def test_get_entropy_t1(client: Client):
_assert_protection(client)
with client:
client.set_expected_responses(
[
messages.ButtonRequest(code=B.ProtectCall),
messages.Entropy,
]
)
misc.get_entropy(client, 10)
@pytest.mark.skip_t1
def test_get_entropy_t2(client: Client):
def test_get_entropy(client: Client):
_assert_protection(client)
with client:
client.use_pin_sequence([PIN4])

@ -17,6 +17,7 @@
"amount": 998060,
"script_type": "SPENDP2SHWITNESS",
"script_sig": "160014209297fb46272a0b7e05139440dbd39daea3e25a",
"witness":"0247304402206f5b2032601278685921b397416cecd5f70cde48b7203bf2a953283c0cd05f4002205fd21a2c318330f11e8433f8fae6b1c4c257a79da55be9712961214ba2752a1f012103c2c2e65556ca4b7371549324b99390725493c8a6792e093a0bdcbb3e2d7df4ab",
"sequence": 4294967295
}
],

@ -17,7 +17,8 @@
"prev_index": 0,
"script_sig": "",
"script_type": "SPENDTAPROOT",
"sequence": 4294967293
"sequence": 4294967293,
"witness": "0140d961a3fc97561c8a305d0ba78488e8d1efed520ac36b226db76277c38e5ab112236a2f821b6dde82dc4013f74148d1ec6e1e471b952755b5265b7ed594afb723"
}
],
"lock_time": 0,

@ -27,6 +27,7 @@
"amount": 839318869,
"script_type": "SPENDP2SHWITNESS",
"script_sig": "160014681ea49259abb892460bf3373e8a0b43d877fa18",
"witness": "02473044022039bb1710e041e9a936bd3adf39f61906ac4363a67d1c29b1a264ff8cf5a0c95102202829307d82141792125480abe6491f0f0c7d675c3d1a06daa383d617afcb53380121028cbc37e1816a23086fa738c8415def477e813e20f484dbbd6f5a33a37c322251",
"sequence": 4294967295
}
],

@ -46,7 +46,7 @@
"T1_bitcoin-test_getaddress.py::test_ltc": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_getaddress.py::test_multisig": "09d812e81c04cef37608f181dcdefb6cd186eb5bb111d47ae0e62d1b3fdd64cf",
"T1_bitcoin-test_getaddress.py::test_multisig_missing[False]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_getaddress.py::test_multisig_missing[True]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_getaddress.py::test_multisig_missing[True]": "ef912e3aed3113ed37f982568c0eca17c27feeb67e87e0f7e43cf8b3b3e8d199",
"T1_bitcoin-test_getaddress.py::test_public_ckd": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_getaddress.py::test_tbtc": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_getaddress.py::test_tgrs": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@ -137,7 +137,7 @@
"T1_bitcoin-test_komodo.py::test_one_one_rewards_claim": "d6ba8441ad5e4bbdb191eef24fd679637e468cf1e7317b290bf89d2588bea214",
"T1_bitcoin-test_multisig.py::test_15_of_15": "ba0a7e6d6a6f37bf553130acc7aa2471d9d7d804f1564837f149b3b5ecec0461",
"T1_bitcoin-test_multisig.py::test_2_of_3": "4ece08d5a19590a521e22aae038a492796922f26bb8ba70614211a6ade5bce18",
"T1_bitcoin-test_multisig.py::test_attack_change_input": "f4f75000bfc3af0006a767e9afbc7f3930bc6bad864ca0d31656735d4103bddc",
"T1_bitcoin-test_multisig.py::test_attack_change_input": "b5beb346018c89e34a219b5466e3f2f257865b8623c356e2b249742d89e04da3",
"T1_bitcoin-test_multisig.py::test_missing_pubkey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_multisig_change.py::test_external_external": "b31515c4102fe602ed1e951bf67db483ffb8874dacc4b0359e9ef67d16999178",
"T1_bitcoin-test_multisig_change.py::test_external_internal": "ceef2445ab95ec10543e320224b13febef2428d240cb01c58dd7ce878b121997",
@ -147,15 +147,15 @@
"T1_bitcoin-test_multisig_change.py::test_multisig_external_external": "988489b219d84517ca69893a8417a480309695549eb83f5821ebd52381e3a3a2",
"T1_bitcoin-test_multisig_change.py::test_multisig_mismatch_change": "10dadffd94e286e588a7006906517205384084c493411191422bed806354caf8",
"T1_bitcoin-test_multisig_change.py::test_multisig_mismatch_inputs": "dc50b96dc2f819f8bdccdb7b3d404580b0e08628e222f59661f91b13120c4ef5",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3]": "e6cfec9182dc6fc7e5b5ae63edf516a3a8db2bec008608e901c19c40c29b47a3",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2]": "e6d5e00fc42472a974be05181a0b071e0b78044bceb2fd02058303303e42edda",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3]": "c968d01488a358a7287c4e631996081bb490ff6e702b5ff84c3addba1c7b0974",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2]": "814c415655b03a6757056456544852a7ec88f8e96fbc97728eba7874d03782f8",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1]": "f1d7f1ba4255576af0ffe4dd11dbc31dda17fec533495992a26bc1d22ade567a",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0]": "df99b6bcfaf86d8ca67713ba64c085fb57b6fc6004494ef1cf83ccb4b57b8d4b",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4]": "670669469e2de75d1164e7a0d5c8ad9c96520b0bf9d7aef85e5796853a375cdd",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths0-address_index0]": "3f11a25075140b6bb74d03d2eaf67559003cf5f46d07a778e2552bb281eaaaa8",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths1-address_index1]": "7c888498d7a49466b2ec128d523f5b7a4af29beccab3e4da8fdf3de2cc3e0e1e",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "44422270a72666e8fd508c86d3654a851aadc797fbb57a1d5c3a7bbc400911d2",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths3-address_index3]": "e694e40bfe527e0488901d20dce70192f866c7aac61787c2220e79be439793f3",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "e8723bbbe5cb2484f3d1eda6fe19c48f23df6e96c36f6ff0d5d9d499ffc034a6",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths3-address_index3]": "3ab904120014545ec65941dbaeb2c12c1659da2db495e62c5b3c4edd0dce3081",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths4-address_index4]": "c245c47efa462d2e6d487d81f131d3ae561c0f30ad90e55b53b48ba8b46ebea1",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths5-address_index5]": "81e4b1b39a135814413c96e9fa4e2639a8ab6b2cb9e945445ee12a99e994b523",
"T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths6-address_index6]": "5d57a31f47490c5738af8136bf9ec8ee9d0db980d1653b9eaedace9d60e74119",
@ -164,20 +164,20 @@
"T1_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-3h-100h-4-255-script_types1]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-4-255-script_types0]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-49-0-63-0-255-script_types4]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-6-255-script_types3]": "ff92edfa61c3e98430d8fd7cd35f67ff237dc2b9d9d0a35256e11a8f81ffa317",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-script_types2]": "6e4c9ae9ab940e6b78862405d585cc1ebb42ecff42aff93af83d66e8b38f2a69",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-6-255-script_types3]": "4f7ee19b4e43a709ba945eb24d6bd2a9fe4785e33d54be937d8e3a2551b8d397",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-script_types2]": "510797e3346491fc7b3eb6f32f05e6b03640ed5cc8f3d70e1d85b77273578972",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-3h-100h-4-255-script_types1]": "bec27ce6240d3be57e2815b00f66db2f3d0da60b3de8429772aed5ce5dc0263a",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-4-255-script_types0]": "8501aeef2b2494e3440d4da64f2d08d24284183c1813753e653039797ffe684f",
"T1_bitcoin-test_nonstandard_paths.py::test_signmessage[m-49-0-63-0-255-script_types4]": "3f99e0c68e5fb612cb48b7d170a5f36a32e1fc5d8fe7d98f391ef4900411731d",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-6-255-script_types3]": "aa7cafa3fdf34ece7b4d7e1ad20c11d40e3582ed0473e1ea82b3fe6d02b151fa",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-script_types2]": "aa7cafa3fdf34ece7b4d7e1ad20c11d40e3582ed0473e1ea82b3fe6d02b151fa",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-6-255-script_types3]": "c8993b0932893430323d4fd34311ff6e13dc69c74247485ee1363fbc8c5b86c6",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-script_types2]": "c8993b0932893430323d4fd34311ff6e13dc69c74247485ee1363fbc8c5b86c6",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-3h-100h-4-255-script_types1]": "aa7cafa3fdf34ece7b4d7e1ad20c11d40e3582ed0473e1ea82b3fe6d02b151fa",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-4-255-script_types0]": "aa7cafa3fdf34ece7b4d7e1ad20c11d40e3582ed0473e1ea82b3fe6d02b151fa",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx[m-49-0-63-0-255-script_types4]": "682610dc7fcea1c969063ed71b33ab36a62e165b331a713aa3b8148ddb5f6e95",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths0-address_index0]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths1-address_index1]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths2-address_index2]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths3-address_index3]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths2-address_index2]": "95cf4ccb223cbe1171033da91fdc05802ceafed068fe7a56fedec000b8c421b4",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths3-address_index3]": "95cf4ccb223cbe1171033da91fdc05802ceafed068fe7a56fedec000b8c421b4",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths4-address_index4]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths5-address_index5]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
"T1_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths6-address_index6]": "5c310bb0a73dc35ae1f2910b47ba319893b9039f1ed9762e67e9a97ebf1b6079",
@ -249,12 +249,13 @@
"T1_bitcoin-test_signtx_amount_unit.py::test_signtx[AmountUnit.MILLIBITCOIN]": "8081910bd937c704fb65226dc85e8fc58a7331102aa036a5a97652638a0bde20",
"T1_bitcoin-test_signtx_amount_unit.py::test_signtx[AmountUnit.SATOSHI]": "a565b50e63776aad284c42c71bf53e5844dff12f159cbd00679b97d2fb74fd20",
"T1_bitcoin-test_signtx_amount_unit.py::test_signtx[None]": "367fd3c75f30f7224435e3309562d210d9ac6809ce2fae392f7fe75070fda094",
"T1_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "9640b4d0bdcde8fec8a4c077e1d12da211d02989458ad34115731237b3dad4f9",
"T1_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "c478ef5c111b38c0fee1f79df1e0d00ecd5c0e81913e59051047cb0db65ece69",
"T1_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "e09b404a39a4594f1b7bdc146bc6b8783f62f6c4568785f1ee8e1eae2d902c65",
"T1_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "3502ca6c3112b694161713d573a5547d3801894a990c108096900b95f689a734",
"T1_bitcoin-test_signtx_invalid_path.py::test_attack_path_segwit": "473636ae4c43d8a349db09187b74eb4c1aa2b7fe02742d5fa928cdbc2a9e4cfd",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail": "75e45c0b6039244afae5cb138aeb4eec2c01e71b91a3ce0d73797ca3b04ca94a",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_pass_forkid": "9c35bfcc194afff453802147f5b4a2d033492e564835be649c3293a62857de59",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_prompt": "57b20ea95e26ee7f675cbb177b9c781389ef36a02f2815f7939ab83c2d0f8f36",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail_asap": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_pass_forkid": "c83cf4f8324514dba0831e96fa2c20c30cef4121dcd594cf3232af19e4721a07",
"T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_prompt": "cbf1b6f66151a120689757e6dcd7af9483ceb19e5aa1dff3e1fb5c6f4be8d292",
"T1_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_inputs": "5b980d57e7d1707d8802bff0665e0460fe5c594c91d758b05ee59020b72e3941",
"T1_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_non_segwit_inputs": "704181fd5aa2ff33a9e5a27874187585ef946f7cdf6e690a7316a33921f25602",
"T1_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_inputs": "5b980d57e7d1707d8802bff0665e0460fe5c594c91d758b05ee59020b72e3941",
@ -263,10 +264,10 @@
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[hello world]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[x]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[]": "9ec64a9408664533abd9b11973f15194a6e4df51abd77a549da8bf67a1f2577c",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[hello world]": "9ec64a9408664533abd9b11973f15194a6e4df51abd77a549da8bf67a1f2577c",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[x]": "9ec64a9408664533abd9b11973f15194a6e4df51abd77a549da8bf67a1f2577c",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "9ec64a9408664533abd9b11973f15194a6e4df51abd77a549da8bf67a1f2577c",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[]": "0aaaaec8e263055e9b26e93e839f8fa57c54f7dcebef9d7f94bc175712317c1d",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[hello world]": "0aaaaec8e263055e9b26e93e839f8fa57c54f7dcebef9d7f94bc175712317c1d",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[x]": "0aaaaec8e263055e9b26e93e839f8fa57c54f7dcebef9d7f94bc175712317c1d",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "0aaaaec8e263055e9b26e93e839f8fa57c54f7dcebef9d7f94bc175712317c1d",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[]": "92816fb27c0fc626348c8ac485990305a824890ea5c862723d6cd53c7b558516",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[hello world]": "92816fb27c0fc626348c8ac485990305a824890ea5c862723d6cd53c7b558516",
"T1_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[x]": "92816fb27c0fc626348c8ac485990305a824890ea5c862723d6cd53c7b558516",
@ -275,11 +276,11 @@
"T1_bitcoin-test_signtx_replacement.py::test_attack_steal_change": "3a79850fe95abbd2ca342fc62ba7f6404c4f437977764839a8146789ac811fce",
"T1_bitcoin-test_signtx_replacement.py::test_p2pkh_fee_bump": "a386c4c61f5fe3b073db6b8725193f5bf7881d7b6fae175ff7d879f7c94eb795",
"T1_bitcoin-test_signtx_replacement.py::test_p2tr_fee_bump": "00f4f745f88f1072f495e513d6a7747db494bb7c785c32d167652fe1d79509be",
"T1_bitcoin-test_signtx_replacement.py::test_p2tr_invalid_signature": "1f46b6ec89be1742dc4649153e6d13b172c9e93be7c91063650f814e631b757c",
"T1_bitcoin-test_signtx_replacement.py::test_p2tr_invalid_signature": "00f4f745f88f1072f495e513d6a7747db494bb7c785c32d167652fe1d79509be",
"T1_bitcoin-test_signtx_replacement.py::test_p2wpkh_finalize": "7b3b6ebee78fed0e64c9689c64c5fbf73099812c5452b2fd2dbe2c23cd69b669",
"T1_bitcoin-test_signtx_replacement.py::test_p2wpkh_in_p2sh_fee_bump_from_external": "3d7d6ad6eafe3399f9d3aa5bb358e4c04f83a98b68ccfa8a124b7e63c0f6df78",
"T1_bitcoin-test_signtx_replacement.py::test_p2wpkh_in_p2sh_remove_change": "14544554428651eb22515a88418c71f66de68e581ea2df5b2259843b1931e8fc",
"T1_bitcoin-test_signtx_replacement.py::test_p2wpkh_invalid_signature": "ee190f0d9f972f005c706a818872a18778aa570737b65e5bebbe6edbe6396008",
"T1_bitcoin-test_signtx_replacement.py::test_p2wpkh_invalid_signature": "7b3b6ebee78fed0e64c9689c64c5fbf73099812c5452b2fd2dbe2c23cd69b669",
"T1_bitcoin-test_signtx_replacement.py::test_p2wpkh_op_return_fee_bump": "897291942225c61f9b641c7a1287960e7c21d80ada6c75414399d76edc41054c",
"T1_bitcoin-test_signtx_segwit.py::test_attack_change_input_address": "fb82fd6c801028181ea89cc517c1401ca78d319b1b9d60e19e5b1cc0107a083f",
"T1_bitcoin-test_signtx_segwit.py::test_attack_mixed_inputs": "614206bc232bf0a07846361bd21a2a0520c8384f052ba362d227e17c33013270",
@ -421,7 +422,7 @@
"T1_misc-test_msg_getentropy.py::test_entropy[8]": "10ee154b5db5599420a26df724cf2301afafb9bdb55429e4e091046881d589cb",
"T1_misc-test_msg_getentropy.py::test_entropy[9]": "10ee154b5db5599420a26df724cf2301afafb9bdb55429e4e091046881d589cb",
"T1_misc-test_msg_signidentity.py::test_sign": "237d6575385f61c32b574a23168330e40025eb9351202698f2d115db0e146934",
"T1_nem-test_getaddress.py::test_nem_getaddress": "e7ee9d6d0fdcf2009703fac7dcde878f72531587c20586d82cd9ca090647fb98",
"T1_nem-test_getaddress.py::test_nem_getaddress": "647dbd437bc7d5913ca7cbc8027d0230c3617e8b266f2c89e63c2d1342313557",
"T1_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation": "74f2ed8d59e1aa1185ef7f06fe63e49380dfb185faa0e0d01656bc2bc8ff8c0c",
"T1_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_levy": "d782d6c77ea579238f6c5fc81adef34e0a47b4006ee4cf4556747ddc4afa998b",
"T1_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_properties": "014cdfbc54f7e6861fbc74e2c5729d6d5ce75b9774130d2cc62de413a96d05c9",
@ -432,9 +433,9 @@
"T1_nem-test_signtx_others.py::test_nem_signtx_importance_transfer": "7a63646daa836594fc56ba6f4d1af5deb0f1ea50c4e931a084ab1636a11546d8",
"T1_nem-test_signtx_others.py::test_nem_signtx_provision_namespace": "11bb4a8dc8991471d8ed896691ebaecd0023b29432976ad519e92ece8f91a96a",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_encrypted_payload": "b1fd9c5250032b2decce6ef18cb1c6e06e9daea279039b58e01cc28a3f4dc765",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "1efa8ae57b72b7a8220b4b9ad02dd0c08e3c9692673ebe7384144ad07fbc20c3",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "2b55781a0940df17fefdaf12ea46d5f794b15c7898f95a3ed82ccf86ec60871f",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "cbd7f2a804a0d5c7014ee1bc484d23009ca78c1e220755ece35e99d444dd6f9d",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "4de1af57a9f25b81ab5d29a6c96e2cd117145aae6cba3fedd083cac7f8cff1d7",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "ebc2635064a4469a98c2a4db2608ec3d006a69386d47e78bbbb8800bb0e7dc2a",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "483194e161e010b5860086054fd1527ab79bbdfbf6fcbf556047a3e7f9d66d6d",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_simple": "3dac9a2abaab139be3b670d6f8e22d34db0171d09101b447c9de7011ad59b465",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_unknown_mosaic": "0fd4bec396dc0850d42a43fb6bd23a751565ef143870ae21e1c1ff5faaeb1bef",
"T1_nem-test_signtx_transfers.py::test_nem_signtx_xem_as_mosaic": "9cc4d7978b6296e0d107a20912e4dedcc9ed6eb3229749a7fb515827c85f18ee",
@ -517,9 +518,9 @@
"T1_test_basic.py::test_device_id_same": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_test_basic.py::test_features": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_test_basic.py::test_ping": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_test_bip32_speed.py::test_cache": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_test_bip32_speed.py::test_private_ckd": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_test_bip32_speed.py::test_public_ckd": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"T1_test_bip32_speed.py::test_cache": "55f043b3e286b778a02baea8f7c3547208849e2e18f90837bd9374a4a14c5c0b",
"T1_test_bip32_speed.py::test_private_ckd": "55f043b3e286b778a02baea8f7c3547208849e2e18f90837bd9374a4a14c5c0b",
"T1_test_bip32_speed.py::test_public_ckd": "55f043b3e286b778a02baea8f7c3547208849e2e18f90837bd9374a4a14c5c0b",
"T1_test_cancel.py::test_cancel_message_via_cancel[message0]": "de7fc40b2f35e82fa486f1b97ee3e34a96d0a67412537e8a0fddacc0b0b1649d",
"T1_test_cancel.py::test_cancel_message_via_cancel[message1]": "af93b5d0a8ae6b297391a43ff3f6382d0bea1109f4f411f5b306e2e7ced6e814",
"T1_test_cancel.py::test_cancel_message_via_initialize[message0]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
@ -568,7 +569,7 @@
"T1_test_protection_levels.py::test_apply_settings": "af9edc0f8ab95a119d48f8ba3dad120dd95459eb8ec01a7cc8e3e5d8cd615981",
"T1_test_protection_levels.py::test_change_pin_t1": "b03b10c08880556b5b5b3909f9d55486b4b27079eb0b56ce339ca020521ab664",
"T1_test_protection_levels.py::test_get_address": "5b7419ecda88e49d9a55af9e7c7dc6d96e5992e11515299c7794de6e2e834eef",
"T1_test_protection_levels.py::test_get_entropy_t1": "8af3b06ff6827712110f4fb4a5ae6dced3d96022065aba9cbcfc50ca769fef19",
"T1_test_protection_levels.py::test_get_entropy": "a858148a335093e46872966e6411cd1bf9d0899bba6a3c798d7535e01461273b",
"T1_test_protection_levels.py::test_get_public_key": "5b7419ecda88e49d9a55af9e7c7dc6d96e5992e11515299c7794de6e2e834eef",
"T1_test_protection_levels.py::test_initialize": "3f4bd58ada8b2be88ceaf45b3653e940bd52f48eb42bd5ee43c0a8c7dd392139",
"T1_test_protection_levels.py::test_passphrase_cached": "79a607736c6833a04561231c8db1df8cf6ac186715fc3798be9cc3456a588e24",
@ -897,9 +898,9 @@
"TT_bitcoin-test_signtx_external.py::test_p2pkh_presigned": "8dd8089941ceb0d82c9425c69d54240f99e3ae7932ef24acd49313d28389b683",
"TT_bitcoin-test_signtx_external.py::test_p2pkh_with_proof": "c09de07fbbf1e047442180e2facb5482d06a1a428891b875b7dd93c9e4704ae1",
"TT_bitcoin-test_signtx_external.py::test_p2tr_external_presigned": "c714c4a4ea8b98dfbdd8185925adafbafc62570f415688972d6003a19d7b4d23",
"TT_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "9919d854e2702be375ad09c74af4fbaaa92d36cc2ed360cc7cfbd196c21a39a6",
"TT_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "b398085c2fa6d4fa1ba97d872f95f3ac2268e9455f5831344f6e34a4badf7a17",
"TT_bitcoin-test_signtx_external.py::test_p2tr_with_proof": "d6723e2243bc38231ec4eb9ed63afd39610460c0d859b4c576b12db1f7915d02",
"TT_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "7780f69c321c49c97ee970617ba91a63a7c375dd5ca3d13dec943c28511fb128",
"TT_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "d178bd3e2cadbe0992904b3d32df963b75e1da801804a471e45a1c5c0a9f2581",
"TT_bitcoin-test_signtx_external.py::test_p2wpkh_in_p2sh_presigned": "8313bff77e41aef142c3b25818ab58dcc7e9d658d38e2e8fc50629ebbe05869b",
"TT_bitcoin-test_signtx_external.py::test_p2wpkh_in_p2sh_with_proof": "c09de07fbbf1e047442180e2facb5482d06a1a428891b875b7dd93c9e4704ae1",
"TT_bitcoin-test_signtx_external.py::test_p2wpkh_presigned": "4608478b1d61415cf0ec93a0ea4397c35d17a91d4b6d25e9c024b77330e398eb",
@ -1560,7 +1561,7 @@
"TT_test_protection_levels.py::test_apply_settings": "2451a804df4a867fef29adf4b71445352a3bface95a797f65bb87cf58c1ef34f",
"TT_test_protection_levels.py::test_change_pin_t2": "d414bdebe6ea6b0f754aec1cdde61133b87fd27cf791ab1bdfdb61866a400d6c",
"TT_test_protection_levels.py::test_get_address": "f0ac110de788b3112e04dc2ef131fca011a8dea1c309df37adeb23066729e273",
"TT_test_protection_levels.py::test_get_entropy_t2": "539ac09590d3252f0ccb2eb836c703a16be5a219c8bd46add57be8319a336ae9",
"TT_test_protection_levels.py::test_get_entropy": "539ac09590d3252f0ccb2eb836c703a16be5a219c8bd46add57be8319a336ae9",
"TT_test_protection_levels.py::test_get_public_key": "f0ac110de788b3112e04dc2ef131fca011a8dea1c309df37adeb23066729e273",
"TT_test_protection_levels.py::test_initialize": "59e518cba8589979f0af46e2acb211d37c96312f1d1a63a899d138ebb2f3ca29",
"TT_test_protection_levels.py::test_passphrase_cached": "7fe34cc300a6f3547eaf72ab4339b758469f1e2722244d2a14d06e55ab1a3716",

Loading…
Cancel
Save