1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-04 21:48:17 +00:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Ioan Bizău
aad4a7d22d
Merge 3bf8f12cd5 into 13df961317 2024-12-02 22:28:03 +01:00
Ioan Bizău
13df961317 refactor(core/ui): introduce show_danger
This is a unified interface for flow_warning_hi_prio,
which was available only on Mercury before.

[no changelog]
2024-12-02 22:28:00 +01:00
Ioan Bizău
3bf8f12cd5 fixup! fixup! feat(core): add libtropic to unix build 2024-11-27 16:19:12 +01:00
Ioan Bizău
14a5770703 fixup! feat(core): add libtropic to unix build 2024-11-27 16:18:42 +01:00
Ioan Bizău
21d26d60df chore(core/tropic): update libtropic. 2024-11-27 15:49:56 +01:00
Ioan Bizău
9567cca9d0 fixup! chore(core/tests): add smoke test for libtropic 2024-11-27 15:49:56 +01:00
Ioan Bizău
ff3f1deac1 fixup! feat(core): add libtropic to unix build 2024-11-27 15:49:56 +01:00
Ioan Bizău
ce62dc6e2a chore(core): add ability for emu launcher to launch tropic model 2024-11-27 15:49:56 +01:00
Ioan Bizău
45891cb799 chore(core/tests): add smoke test for libtropic 2024-11-27 15:49:56 +01:00
Ioan Bizău
d316d88c0f feat(core): add libtropic to unix build 2024-11-27 15:49:52 +01:00
28 changed files with 810 additions and 390 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ __pycache__/
proto.gv*
.DS_Store
crypto/tests/libtrezor-crypto.so.dSYM/
tropic-model/

4
.gitmodules vendored
View File

@ -27,7 +27,9 @@
[submodule "vendor/cmsis_5"]
path = vendor/cmsis_5
url = https://github.com/ARM-software/CMSIS_5.git
[submodule "vendor/stm32u5xx_hal_driver"]
path = vendor/stm32u5xx_hal_driver
url = https://github.com/trezor/stm32u5xx_hal_driver.git
[submodule "vendor/libtropic"]
path = vendor/libtropic
url = https://github.com/tropicsquare/libtropic.git

View File

@ -681,6 +681,7 @@ if FROZEN:
use_button='button' in FEATURES_AVAILABLE,
use_touch='touch' in FEATURES_AVAILABLE,
ui_layout=ui.get_ui_layout(TREZOR_MODEL),
tropic='tropic' in FEATURES_AVAILABLE,
thp=THP,
)

View File

@ -21,7 +21,7 @@ if BENCHMARK and PYOPT != '0':
print("BENCHMARK=1 works only with PYOPT=0.")
exit(1)
FEATURES_WANTED = ["input", "sd_card", "dma2d", "optiga"]
FEATURES_WANTED = ["input", "sd_card", "dma2d", "optiga", "tropic"]
if not models.has_emulator(TREZOR_MODEL):
# skip unix build
@ -48,6 +48,7 @@ SOURCE_MOD = [
'vendor/micropython/extmod/vfs_posix_file.c',
]
SOURCE_MOD_CRYPTO = []
SOURCE_MOD_TROPIC = []
RUST_UI_FEATURES = []
# modtrezorconfig
@ -251,6 +252,14 @@ SOURCE_MOD += [
'embed/upymod/modutime.c',
]
SOURCE_MOD_TROPIC += [
'vendor/libtropic/src/libtropic.c',
]
CPPDEFINES_MOD += ['USE_TREZOR_CRYPTO']
CPPPATH_MOD += ['vendor/libtropic/src/', 'vendor/libtropic/include/']
SOURCE_MICROPYTHON = [
'vendor/micropython/extmod/modubinascii.c',
'vendor/micropython/extmod/moductypes.c',
@ -752,6 +761,7 @@ if FROZEN:
bitcoin_only=BITCOIN_ONLY,
backlight='backlight' in FEATURES_AVAILABLE,
optiga='optiga' in FEATURES_AVAILABLE,
tropic='tropic' in FEATURES_AVAILABLE,
use_button='button' in FEATURES_AVAILABLE,
use_touch='touch' in FEATURES_AVAILABLE,
ui_layout=ui.get_ui_layout(TREZOR_MODEL),
@ -769,7 +779,7 @@ if FROZEN:
#
obj_program = []
source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_MICROPYTHON + SOURCE_UNIX
source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_MOD_TROPIC + SOURCE_MICROPYTHON + SOURCE_UNIX
obj_program.extend(env.Object(source=SOURCE_MOD))
obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero'))
if FEATURE_FLAGS["SECP256K1_ZKP"]:

View File

@ -40,6 +40,7 @@ rgb_led = []
backlight = []
usb = []
optiga = []
tropic = []
translations = ["crypto"]
test = [
"backlight",

View File

@ -262,7 +262,6 @@ static void _librust_qstrs(void) {
MP_QSTR_flow_request_number;
MP_QSTR_flow_request_passphrase;
MP_QSTR_flow_show_share_words;
MP_QSTR_flow_warning_hi_prio;
MP_QSTR_get_language;
MP_QSTR_get_transition_out;
MP_QSTR_haptic_feedback__disable;
@ -652,6 +651,7 @@ static void _librust_qstrs(void) {
MP_QSTR_share_words__wrote_down_all;
MP_QSTR_show_address_details;
MP_QSTR_show_checklist;
MP_QSTR_show_danger;
MP_QSTR_show_error;
MP_QSTR_show_group_share_success;
MP_QSTR_show_homescreen;

View File

@ -12,10 +12,10 @@ pub mod prompt_backup;
pub mod request_number;
pub mod request_passphrase;
pub mod set_brightness;
pub mod show_danger;
pub mod show_share_words;
pub mod show_tutorial;
pub mod util;
pub mod warning_hi_prio;
pub use confirm_action::{
new_confirm_action, new_confirm_action_simple, ConfirmActionExtra, ConfirmActionMenuStrings,
@ -34,7 +34,7 @@ pub use prompt_backup::PromptBackup;
pub use request_number::RequestNumber;
pub use request_passphrase::RequestPassphrase;
pub use set_brightness::SetBrightness;
pub use show_danger::ShowDanger;
pub use show_share_words::ShowShareWords;
pub use show_tutorial::ShowTutorial;
pub use util::{ConfirmBlobParams, ShowInfoParams};
pub use warning_hi_prio::WarningHiPrio;

View File

@ -22,13 +22,13 @@ use super::super::{
};
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum WarningHiPrio {
pub enum ShowDanger {
Message,
Menu,
Cancelled,
}
impl FlowController for WarningHiPrio {
impl FlowController for ShowDanger {
#[inline]
fn index(&'static self) -> usize {
*self as usize
@ -57,7 +57,7 @@ impl FlowController for WarningHiPrio {
const EXTRA_PADDING: i16 = 6;
pub fn new_warning_hi_prio(
pub fn new_show_danger(
title: TString<'static>,
description: TString<'static>,
value: TString<'static>,
@ -106,9 +106,9 @@ pub fn new_warning_hi_prio(
.with_result_icon(theme::ICON_BULLET_CHECKMARK, theme::GREY_DARK)
.map(|_| Some(FlowMsg::Cancelled));
let res = SwipeFlow::new(&WarningHiPrio::Message)?
.with_page(&WarningHiPrio::Message, content_message)?
.with_page(&WarningHiPrio::Menu, content_menu)?
.with_page(&WarningHiPrio::Cancelled, content_cancelled)?;
let res = SwipeFlow::new(&ShowDanger::Message)?
.with_page(&ShowDanger::Message, content_message)?
.with_page(&ShowDanger::Menu, content_menu)?
.with_page(&ShowDanger::Cancelled, content_cancelled)?;
Ok(res)
}

View File

@ -1491,7 +1491,7 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
panic!();
}
extern "C" fn new_warning_hi_prio(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
extern "C" fn new_show_danger(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
@ -1501,8 +1501,7 @@ extern "C" fn new_warning_hi_prio(n_args: usize, args: *const Obj, kwargs: *mut
.unwrap_or_else(|_| Obj::const_none())
.try_into_option()?;
let flow =
flow::warning_hi_prio::new_warning_hi_prio(title, description, value, verb_cancel)?;
let flow = flow::show_danger::new_show_danger(title, description, value, verb_cancel)?;
Ok(LayoutObj::new_root(flow)?.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
@ -1717,6 +1716,16 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// """Warning modal. No buttons shown when `button` is empty string."""
Qstr::MP_QSTR_show_warning => obj_fn_kw!(0, new_show_warning).as_obj(),
/// def show_danger(
/// *,
/// title: str,
/// description: str,
/// value: str = "",
/// verb_cancel: str | None = None,
/// ) -> LayoutObj[UiResult]:
/// """Warning modal that makes it easier to cancel than to continue."""
Qstr::MP_QSTR_show_danger => obj_fn_kw!(0, new_show_danger).as_obj(),
/// def show_success(
/// *,
/// title: str,
@ -1971,16 +1980,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// """Get address / receive funds."""
Qstr::MP_QSTR_flow_get_address => obj_fn_kw!(0, new_get_address).as_obj(),
/// def flow_warning_hi_prio(
/// *,
/// title: str,
/// description: str,
/// value: str = "",
/// verb_cancel: str | None = None,
/// ) -> LayoutObj[UiResult]:
/// """Warning modal with multiple steps to confirm."""
Qstr::MP_QSTR_flow_warning_hi_prio => obj_fn_kw!(0, new_warning_hi_prio).as_obj(),
/// def flow_confirm_output(
/// *,
/// title: str | None,

View File

@ -0,0 +1,234 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if USE_TROPIC
// Default initial Tropic handshake keys
#define PKEY_INDEX_BYTE PAIRING_KEY_SLOT_INDEX_0
#define SHiPRIV_BYTES \
{0xf0, 0xc4, 0xaa, 0x04, 0x8f, 0x00, 0x13, 0xa0, 0x96, 0x84, 0xdf, \
0x05, 0xe8, 0xa2, 0x2e, 0xf7, 0x21, 0x38, 0x98, 0x28, 0x2b, 0xa9, \
0x43, 0x12, 0xf3, 0x13, 0xdf, 0x2d, 0xce, 0x8d, 0x41, 0x64};
#define SHiPUB_BYTES \
{0x84, 0x2f, 0xe3, 0x21, 0xa8, 0x24, 0x74, 0x08, 0x37, 0x37, 0xff, \
0x2b, 0x9b, 0x88, 0xa2, 0xaf, 0x42, 0x44, 0x2d, 0xb0, 0xd8, 0xaa, \
0xcc, 0x6d, 0xc6, 0x9e, 0x99, 0x53, 0x33, 0x44, 0xb2, 0x46};
#include "libtropic.h"
/// package: trezorcrypto.tropic
/// class TropicError(Exception):
/// """Error returned by the Tropic Square chip."""
MP_DEFINE_EXCEPTION(TropicError, Exception)
#define PING_MSG_MAX_LEN 64
#define ECC_SLOT_COUNT 32
#define SIG_SIZE 64
STATIC bool lt_handle_initialized = false;
STATIC lt_handle_t lt_handle = {0};
STATIC void tropic_init(lt_handle_t *handle) {
lt_ret_t ret = LT_FAIL;
ret = lt_init(handle);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_init failed.");
}
uint8_t X509_cert[LT_L2_GET_INFO_REQ_CERT_SIZE] = {0};
ret = lt_get_info_cert(handle, X509_cert, LT_L2_GET_INFO_REQ_CERT_SIZE);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_get_info_cert failed.");
}
uint8_t stpub[32] = {0};
ret = lt_cert_verify_and_parse(X509_cert, 512, stpub);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_cert_verify_and_parse failed.");
}
uint8_t pkey_index = PKEY_INDEX_BYTE;
uint8_t shipriv[] = SHiPRIV_BYTES;
uint8_t shipub[] = SHiPUB_BYTES;
ret = lt_session_start(handle, stpub, pkey_index, shipriv, shipub);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_session_start failed.");
}
}
/// def ping(message: str) -> str:
/// """
/// Test the session by pinging the chip.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_ping(mp_obj_t message) {
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
uint8_t msg_in[PING_MSG_MAX_LEN] = {0};
mp_buffer_info_t message_b = {0};
mp_get_buffer_raise(message, &message_b, MP_BUFFER_READ);
if (message_b.len > 0) {
ret = lt_ping(&lt_handle, (uint8_t *)message_b.buf, (uint8_t *)msg_in,
message_b.len);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_ping failed.");
}
} else {
return mp_const_none;
}
vstr_t result = {0};
vstr_init_len(&result, message_b.len);
memcpy(result.buf, msg_in, message_b.len);
result.len = strlen(result.buf);
return mp_obj_new_str_from_vstr(&mp_type_str, &result);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_tropic_ping_obj,
mod_trezorcrypto_tropic_ping);
/// def get_certificate() -> bytes:
/// """
/// Return the chip's certificate.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_get_certificate() {
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
uint8_t X509_cert[512] = {0};
ret = lt_get_info_cert(&lt_handle, X509_cert, 512);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_get_info_cert failed.");
}
vstr_t vstr = {0};
vstr_init_len(&vstr, 512);
memcpy(vstr.buf, X509_cert, 512);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_tropic_get_certificate_obj,
mod_trezorcrypto_tropic_get_certificate);
/// def key_generate(
/// key_index: int,
/// ) -> None:
/// """
/// Generate ECC key in the device's ECC key slot.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_key_generate(mp_obj_t key_index) {
mp_int_t idx = mp_obj_get_int(key_index);
if (idx < 0 || idx >= ECC_SLOT_COUNT) {
mp_raise_ValueError("Invalid index.");
}
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
ret = lt_ecc_key_generate(&lt_handle, idx, CURVE_ED25519);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_ecc_key_generate failed.");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_tropic_key_generate_obj,
mod_trezorcrypto_tropic_key_generate);
/// def sign(
/// key_index: int,
/// digest: bytes,
/// ) -> bytes:
/// """
/// Uses the private key at key_index to produce a signature of the digest.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_sign(mp_obj_t key_index,
mp_obj_t digest) {
mp_int_t idx = mp_obj_get_int(key_index);
if (idx < 0 || idx >= ECC_SLOT_COUNT) {
mp_raise_ValueError("Invalid index.");
}
mp_buffer_info_t dig = {0};
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (dig.len != 32) {
mp_raise_ValueError("Invalid length of digest.");
}
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
vstr_t sig = {0};
vstr_init_len(&sig, SIG_SIZE);
ret = lt_ecc_eddsa_sign(&lt_handle, idx, (const uint8_t *)dig.buf, dig.len,
((uint8_t *)sig.buf), SIG_SIZE);
if (ret != LT_OK) {
vstr_clear(&sig);
mp_raise_msg(&mp_type_TropicError, "lt_ecc_eddsa_sign failed.");
}
sig.len = SIG_SIZE;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_tropic_sign_obj,
mod_trezorcrypto_tropic_sign);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_tropic_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_tropic)},
{MP_ROM_QSTR(MP_QSTR_ping), MP_ROM_PTR(&mod_trezorcrypto_tropic_ping_obj)},
{MP_ROM_QSTR(MP_QSTR_get_certificate),
MP_ROM_PTR(&mod_trezorcrypto_tropic_get_certificate_obj)},
{MP_ROM_QSTR(MP_QSTR_key_generate),
MP_ROM_PTR(&mod_trezorcrypto_tropic_key_generate_obj)},
{MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_tropic_sign_obj)},
{MP_ROM_QSTR(MP_QSTR_TropicError), MP_ROM_PTR(&mp_type_TropicError)}};
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_tropic_globals,
mod_trezorcrypto_tropic_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_tropic_module = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_tropic_globals,
};
#endif

View File

@ -69,6 +69,9 @@ static void wrapped_ui_wait_callback(uint32_t current, uint32_t total) {
#ifdef USE_OPTIGA
#include "modtrezorcrypto-optiga.h"
#endif
#ifdef USE_TROPIC
#include "modtrezorcrypto-tropic.h"
#endif
#if !BITCOIN_ONLY
#include "modtrezorcrypto-cardano.h"
#include "modtrezorcrypto-monero.h"
@ -135,6 +138,9 @@ STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = {
#if USE_OPTIGA
{MP_ROM_QSTR(MP_QSTR_optiga), MP_ROM_PTR(&mod_trezorcrypto_optiga_module)},
#endif
#if USE_TROPIC
{MP_ROM_QSTR(MP_QSTR_tropic), MP_ROM_PTR(&mod_trezorcrypto_tropic_module)},
#endif
};
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorcrypto_globals,
mp_module_trezorcrypto_globals_table);

View File

@ -388,6 +388,8 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = {
/// """Whether the hardware supports haptic feedback."""
/// USE_OPTIGA: bool
/// """Whether the hardware supports Optiga secure element."""
/// USE_TROPIC: bool
/// """Whether the hardware supports Tropic Square secure element."""
/// USE_TOUCH: bool
/// """Whether the hardware supports touch screen."""
/// USE_BUTTON: bool
@ -458,6 +460,11 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else
{MP_ROM_QSTR(MP_QSTR_USE_OPTIGA), mp_const_false},
#endif
#ifdef USE_TROPIC
{MP_ROM_QSTR(MP_QSTR_USE_TROPIC), mp_const_true},
#else
{MP_ROM_QSTR(MP_QSTR_USE_TROPIC), mp_const_false},
#endif
#ifdef USE_TOUCH
{MP_ROM_QSTR(MP_QSTR_USE_TOUCH), mp_const_true},
#else

View File

@ -112,6 +112,7 @@ def _from_env(name: str) -> bool:
@click.option("-G", "--alloc-profiling/--no-alloc-profiling", default=_from_env("TREZOR_MEMPERF"), help="Profile memory allocation (requires special micropython build)")
@click.option("-h", "--headless", is_flag=True, help="Headless mode (no display, disables animation)")
@click.option("--heap-size", metavar="SIZE", default="20M", help="Configure heap size")
@click.option("-m", "--tropic-model", is_flag=True, help="Start the Tropic Square model, needed for running the Tropic tests. Needs to be installed first.")
@click.option("--main", help="Path to python main file")
@click.option("--mnemonic", "mnemonics", multiple=True, help="Initialize device with given mnemonic. Specify multiple times for Shamir shares.")
@click.option("--log-memory/--no-log-memory", default=_from_env("TREZOR_LOG_MEMORY"), help="Print memory usage after workflows")
@ -139,6 +140,7 @@ def cli(
alloc_profiling: bool,
headless: bool,
heap_size: str,
tropic_model: bool,
main: str,
mnemonics: list[str],
log_memory: bool,
@ -177,7 +179,7 @@ def cli(
if command and not run_command:
raise click.ClickException("Extra arguments found. Did you mean to use -c?")
if watch and (command or debugger):
if watch and (command or debugger or tropic_model):
raise click.ClickException("Cannot use -w together with -c or -D")
if watch and inotify is None:
@ -297,6 +299,10 @@ def cli(
emulator.client, record_dir, report_func=print
)
if tropic_model:
run_command = True
command = "./tropic-model.sh"
if run_command:
ret = run_command_with_emulator(emulator, command)
elif watch:

View File

@ -0,0 +1,31 @@
from typing import *
# upymod/modtrezorcrypto/modtrezorcrypto-tropic.h
class TropicError(Exception):
"""Error returned by the Tropic Square chip."""
def ping(message: str) -> str:
"""
Test the session by pinging the chip.
"""
def get_certificate() -> bytes:
"""
Return the chip's certificate.
"""
def key_generate(
key_index: int,
) -> None:
"""
Generate ECC key in the device's ECC key slot.
"""
def sign(
key_index: int,
digest: bytes,
) -> bytes:
"""
Uses the private key at key_index to produce a signature of the digest.
"""

View File

@ -216,6 +216,17 @@ def show_warning(
"""Warning modal. No buttons shown when `button` is empty string."""
# rust/src/ui/model_mercury/layout.rs
def show_danger(
*,
title: str,
description: str,
value: str = "",
verb_cancel: str | None = None,
) -> LayoutObj[UiResult]:
"""Warning modal that makes it easier to cancel than to continue."""
# rust/src/ui/model_mercury/layout.rs
def show_success(
*,
@ -497,17 +508,6 @@ def flow_get_address(
"""Get address / receive funds."""
# rust/src/ui/model_mercury/layout.rs
def flow_warning_hi_prio(
*,
title: str,
description: str,
value: str = "",
verb_cancel: str | None = None,
) -> LayoutObj[UiResult]:
"""Warning modal with multiple steps to confirm."""
# rust/src/ui/model_mercury/layout.rs
def flow_confirm_output(
*,

View File

@ -130,6 +130,8 @@ USE_HAPTIC: bool
"""Whether the hardware supports haptic feedback."""
USE_OPTIGA: bool
"""Whether the hardware supports Optiga secure element."""
USE_TROPIC: bool
"""Whether the hardware supports Tropic Square secure element."""
USE_TOUCH: bool
"""Whether the hardware supports touch screen."""
USE_BUTTON: bool

View File

@ -55,6 +55,27 @@ def configure(
features_available.append("optiga")
defines += [("USE_OPTIGA", "1")]
if "tropic" in features_wanted:
sources += [
"vendor/libtropic/src/libtropic.c",
"vendor/libtropic/src/lt_crc16.c",
"vendor/libtropic/src/lt_hkdf.c",
"vendor/libtropic/src/lt_l1.c",
"vendor/libtropic/src/lt_l1_port_wrap.c",
"vendor/libtropic/src/lt_l2.c",
"vendor/libtropic/src/lt_l2_frame_check.c",
"vendor/libtropic/src/lt_l3.c",
"vendor/libtropic/src/lt_random.c",
"vendor/libtropic/hal/port/unix/lt_port_unix.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_aesgcm.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_ed25519.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_sha256.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_x25519.c",
]
defines += ["USE_TREZOR_CRYPTO"]
features_available.append("tropic")
defines += ["USE_TROPIC=1"]
if "input" in features_wanted:
sources += ["embed/io/touch/unix/touch.c"]
paths += ["embed/io/touch/inc"]

View File

@ -44,6 +44,7 @@ def generate(env):
btc_only = env["bitcoin_only"] == "1"
backlight = env["backlight"]
optiga = env["optiga"]
tropic = env["tropic"]
layout_tt = env["ui_layout"] == "UI_LAYOUT_TT"
layout_tr = env["ui_layout"] == "UI_LAYOUT_TR"
touch = env["use_touch"]
@ -55,6 +56,7 @@ def generate(env):
rf"-e 's/utils\.BITCOIN_ONLY/{btc_only}/g'",
rf"-e 's/utils\.USE_BACKLIGHT/{backlight}/g'",
rf"-e 's/utils\.USE_OPTIGA/{optiga}/g'",
rf"-e 's/utils\.USE_TROPIC/{tropic}/g'",
rf"-e 's/utils\.UI_LAYOUT == \"TT\"/{layout_tt}/g'",
rf"-e 's/utils\.UI_LAYOUT == \"TR\"/{layout_tr}/g'",
rf"-e 's/utils\.UI_LAYOUT == \"MERCURY\"/{layout_mercury}/g'",

View File

@ -22,5 +22,8 @@ if not utils.BITCOIN_ONLY:
if utils.USE_OPTIGA:
from trezorcrypto import optiga # noqa: F401
if utils.USE_TROPIC:
from trezorcrypto import tropic # noqa: F401
if utils.USE_THP:
from trezorcrypto import elligator2 # noqa: F401

View File

@ -119,29 +119,27 @@ def confirm_path_warning(
if not path_type
else f"{TR.words__unknown} {path_type.lower()}."
)
return raise_if_not_confirmed(
trezorui2.flow_warning_hi_prio(
title=f"{TR.words__warning}!", description=description, value=path
),
return show_danger(
"path_warning",
description,
value=path,
verb_cancel=TR.words__cancel_and_exit,
br_code=ButtonRequestType.UnknownDerivationPath,
)
def confirm_multisig_warning() -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.flow_warning_hi_prio(
title=f"{TR.words__important}!",
description=TR.send__receiving_to_multisig,
),
return show_danger(
"warning_multisig",
br_code=ButtonRequestType.Warning,
TR.send__receiving_to_multisig,
title=TR.words__important,
verb_cancel=TR.words__cancel_and_exit,
)
def confirm_multisig_different_paths_warning() -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.flow_warning_hi_prio(
trezorui2.show_danger(
title=f"{TR.words__important}!",
description="Using different paths for different XPUBs.",
),
@ -327,6 +325,28 @@ def show_warning(
)
def show_danger(
br_name: str,
content: str,
value: str | None = None,
title: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
) -> Awaitable[None]:
title = title or TR.words__warning
verb_cancel = verb_cancel or TR.buttons__cancel
return raise_if_not_confirmed(
trezorui2.show_danger(
title=title,
description=content,
value=(value or ""),
verb_cancel=verb_cancel,
),
br_name,
br_code,
)
def show_success(
br_name: str,
content: str,
@ -724,14 +744,10 @@ def _confirm_summary(
if not utils.BITCOIN_ONLY:
def confirm_ethereum_unknown_contract_warning() -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.flow_warning_hi_prio(
title=TR.words__warning,
description=TR.ethereum__unknown_contract_address,
verb_cancel=TR.send__cancel_sign,
),
return show_danger(
"unknown_contract_warning",
ButtonRequestType.Warning,
TR.ethereum__unknown_contract_address,
verb_cancel=TR.send__cancel_sign,
)
async def confirm_ethereum_tx(

View File

@ -420,6 +420,24 @@ def show_warning(
)
def show_danger(
br_name: str,
content: str,
value: str | None = None,
title: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
) -> Awaitable[ui.UiResult]:
title = title or TR.words__warning
return show_warning(
br_name,
title,
content,
TR.words__continue_anyway,
br_code=br_code,
)
def show_success(
br_name: str,
content: str,
@ -564,7 +582,6 @@ def confirm_blob(
title: str,
data: bytes | str,
description: str | None = None,
text_mono: bool = True,
subtitle: str | None = None,
verb: str | None = None,
verb_cancel: str | None = None, # icon
@ -815,11 +832,8 @@ def confirm_total(
if not utils.BITCOIN_ONLY:
def confirm_ethereum_unknown_contract_warning() -> Awaitable[ui.UiResult]:
return show_warning(
"unknown_contract_warning",
TR.words__warning,
TR.ethereum__unknown_contract_address_short,
TR.words__continue_anyway,
return show_danger(
"unknown_contract_warning", TR.ethereum__unknown_contract_address_short
)
async def confirm_ethereum_staking_tx(

View File

@ -372,6 +372,22 @@ def show_warning(
)
def show_danger(
br_name: str,
content: str,
value: str | None = None,
title: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
) -> Awaitable[None]:
return show_warning(
br_name,
content,
TR.words__continue_anyway_question,
br_code=br_code,
)
def show_success(
br_name: str,
content: str,
@ -779,10 +795,8 @@ def _confirm_summary(
if not utils.BITCOIN_ONLY:
def confirm_ethereum_unknown_contract_warning() -> Awaitable[None]:
return show_warning(
"unknown_contract_warning",
TR.ethereum__unknown_contract_address_short,
TR.words__continue_anyway_question,
return show_danger(
"unknown_contract_warning", TR.ethereum__unknown_contract_address_short
)
async def confirm_ethereum_tx(

View File

@ -14,6 +14,7 @@ from trezorutils import ( # noqa: F401
USE_BUTTON,
USE_HAPTIC,
USE_OPTIGA,
USE_TROPIC,
USE_SD_CARD,
USE_THP,
USE_TOUCH,

View File

@ -0,0 +1,27 @@
from common import * # isort:skip
from slip39_vectors import vectors
from trezor.crypto import tropic
class TestCryptoTropic(unittest.TestCase):
def test_ping(self):
self.assertEqual(tropic.ping("HeLlO!"), "HeLlO!")
def test_get_certificate(self):
self.assertEqual(len(tropic.get_certificate()), 512)
def test_sign(self):
try:
tropic.sign(0, "ASD")
assert False
except ValueError as e:
self.assertIn("invalid length", str(e).lower())
tropic.key_generate(0)
# signing should work now that we have a key
self.assertEqual(len(tropic.sign(0, "a" * 32)), 64)
if __name__ == "__main__":
unittest.main()

20
core/tropic-model.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
if [ ! -d "tropic-model" ]; then
echo "================================================="
echo "Please install the Tropic model to the tropic-model/ directory first, using the steps below!"
echo "1. mkdir tropic-model && python3 -mvenv tropic-model/venv && source tropic-model/venv/bin/activate"
echo "2. Follow instructions here: https://github.com/tropicsquare/ts-tvl/tree/master?tab=readme-ov-file#installing"
echo " (basically, download the tvl-XXX.whl and pip install it under the venv created above - which should be already activated)"
echo "3. Get config files for the model from https://github.com/tropicsquare/ts-tvl/tree/master/tvl/server/model_config"
echo " i. model_config.yml"
echo " ii. tropic01_ese_certificate_1.pem"
echo " iii.tropic01_ese_private_key_1.pem"
echo " iv. tropic01_ese_public_key_1.pem"
echo "================================================="
exit 1
fi
cd tropic-model
source venv/bin/activate
model_server tcp -vv -c model_config.yml

1
core/vendor/libtropic vendored Symbolic link
View File

@ -0,0 +1 @@
../../vendor/libtropic/

View File

@ -165,6 +165,7 @@ CFLAGS += -I../vendor/nanopb -Iprotob -DPB_FIELD_16BIT=1 -DPB_ENCODE_ARRAYS_UNPA
CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"'
CFLAGS += -DUSE_MONERO=0
CFLAGS += -DUSE_OPTIGA=0
CFLAGS += -DUSE_TROPIC=0
ifneq ($(BITCOIN_ONLY),1)
CFLAGS += -DUSE_ETHEREUM=1
CFLAGS += -DUSE_NEM=1

File diff suppressed because it is too large Load Diff