refactor(core): introduce "n4w1" feature in SConscript
What changed, and why it matters
This is a clean-up change in the build system for the Trezor hardware wallet firmware. It introduces a dedicated feature flag called 'n4w1' so the code no longer decides behavior based on the hard-coded device model 'T3W1'. There is no user-facing behavior change and no security fix or vulnerability introduced.
No security action required. Treat as ordinary build-system refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors SCons build scripts to add an N4W1 feature toggle. It wires the toggle through Makefile variables, SConscript firmware/unix builds, Rust Cargo features, MicroPython module constants, type stubs, model-specific configuration files, and a source-line preprocessing step. The only runtime logic change replaces two ‘INTERNAL_MODEL == T3W1’ checks with ‘USE_N4W1’ in the debug app. The commit is explicitly marked as a refactor with no changelog.
Changed components
core/Makefilecore/SConscript.firmwarecore/SConscript.unixcore/embed/rust/Cargo.tomlcore/embed/upymod/modtrezorutils/modtrezorutils.ccore/mocks/generated/trezorutils.pyicore/site_scons/models/T3W1/emulator.pycore/site_scons/models/T3W1/trezor_t3w1_revA.pycore/site_scons/models/T3W1/trezor_t3w1_revB.pycore/site_scons/models/T3W1/trezor_t3w1_revC.pycore/site_scons/site_tools/micropython/__init__.pycore/src/apps/debug/__init__.pycore/src/trezor/utils.pyInspect captured patch +50 / −5
diff --git a/core/Makefile b/core/Makefile
index 2ce03a58..a1b2275d 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -50,6 +50,7 @@ STORAGE_INSECURE_TESTING_MODE ?= 0
UI_PERFORMANCE_OVERLAY ?= 0
DBG_CONSOLE ?=
EXTAPP_SUPPORT ?= 0
+N4W1 ?= 0
# If set, VCP writes will be blocking, in order to allow reliable debug data transmission over VCP.
# Disabled by default, to prevent debug firmware from getting stuck while writing log messages (if the host is not reading them).
@@ -147,7 +148,8 @@ SCONS_VARS = \
UI_PERFORMANCE_OVERLAY="$(UI_PERFORMANCE_OVERLAY)" \
BLOCK_ON_VCP="$(BLOCK_ON_VCP)" \
DBG_CONSOLE="$(DBG_CONSOLE)" \
- EXTAPP_SUPPORT="$(EXTAPP_SUPPORT)"
+ EXTAPP_SUPPORT="$(EXTAPP_SUPPORT)" \
+ N4W1="$(N4W1)"
ifdef DISABLE_OPTIGA
SCONS_VARS += DISABLE_OPTIGA="$(DISABLE_OPTIGA)"
diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index a579e003..d9cf493f 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -28,6 +28,7 @@ BLOCK_ON_VCP = ARGUMENTS.get('BLOCK_ON_VCP', '0') == '1'
UI_PERFORMANCE_OVERLAY = ARGUMENTS.get('UI_PERFORMANCE_OVERLAY', '0') == '1'
DBG_CONSOLE = ARGUMENTS.get('DBG_CONSOLE', '')
EXTAPP_SUPPORT = ARGUMENTS.get('EXTAPP_SUPPORT', '0') == '1'
+N4W1 = ARGUMENTS.get('N4W1', '0') == '1'
STORAGE_INSECURE_TESTING_MODE = ARGUMENTS.get('STORAGE_INSECURE_TESTING_MODE', '0') == '1'
if STORAGE_INSECURE_TESTING_MODE and PRODUCTION:
@@ -97,6 +98,10 @@ if DBG_CONSOLE != "":
if TREZOR_MODEL in ['T3W1'] and EXTAPP_SUPPORT:
FEATURES_WANTED += ["app_loading"]
+if N4W1:
+ assert PYOPT == "0", "N4W1 requires PYOPT=0"
+ FEATURES_WANTED += ["n4w1"]
+
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
@@ -486,6 +491,7 @@ SDCARD = ('sd_card' in FEATURES_AVAILABLE)
OPTIGA = ('optiga' in FEATURES_AVAILABLE)
SERIAL_NUMBER = ('serial_number' in FEATURES_AVAILABLE)
BACKLIGHT = ('backlight' in FEATURES_AVAILABLE)
+N4W1 = ('n4w1' in FEATURES_AVAILABLE)
env.Tool('micropython')
@@ -740,7 +746,7 @@ if FROZEN:
)
))
if PYOPT == '0':
- exclude_n4w1 = [SOURCE_PY_DIR + 'apps/debug/n4w1_mock.py'] if TREZOR_MODEL != "T3W1" else []
+ exclude_n4w1 = [SOURCE_PY_DIR + 'apps/debug/n4w1_mock.py'] if not N4W1 else []
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/debug/*.py', exclude=exclude_n4w1))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/homescreen/*.py',
exclude=[
@@ -857,6 +863,7 @@ if FROZEN:
ui_layout=ui.get_ui_layout(TREZOR_MODEL),
thp=THP,
power_manager='power_manager' in FEATURES_AVAILABLE,
+ n4w1=N4W1,
include_source_lines=MICROPY_ENABLE_SOURCE_LINE,
)
diff --git a/core/SConscript.unix b/core/SConscript.unix
index 73dd6bf3..468089db 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -20,6 +20,7 @@ RASPI = os.getenv('TREZOR_EMULATOR_RASPI') == '1'
MICROPY_ENABLE_SOURCE_LINE = ARGUMENTS.get('MICROPY_ENABLE_SOURCE_LINE', '1') == '1'
DBG_CONSOLE = ARGUMENTS.get('DBG_CONSOLE', '')
EXTAPP_SUPPORT = ARGUMENTS.get('EXTAPP_SUPPORT', '0') == '1'
+N4W1 = ARGUMENTS.get('N4W1', '0') == '1'
if DEBUGLINK or PYOPT == '0':
@@ -68,6 +69,10 @@ if not DISABLE_TROPIC:
if TREZOR_MODEL in ['T3W1'] and EXTAPP_SUPPORT:
FEATURES_WANTED += ["app_loading"]
+if N4W1:
+ assert PYOPT == "0", "N4W1 requires PYOPT=0"
+ FEATURES_WANTED += ["n4w1"]
+
if not models.has_emulator(TREZOR_MODEL):
# skip unix build
env = Environment()
@@ -469,6 +474,7 @@ SDCARD = ('sd_card' in FEATURES_AVAILABLE)
OPTIGA = ('optiga' in FEATURES_AVAILABLE)
SERIAL_NUMBER = ('serial_number' in FEATURES_AVAILABLE)
BACKLIGHT = ('backlight' in FEATURES_AVAILABLE)
+N4W1 = ('n4w1' in FEATURES_AVAILABLE)
env.Tool('micropython')
@@ -755,7 +761,7 @@ if FROZEN:
)
))
if PYOPT == '0':
- exclude_n4w1 = [SOURCE_PY_DIR + 'apps/debug/n4w1_mock.py'] if TREZOR_MODEL != "T3W1" else []
+ exclude_n4w1 = [SOURCE_PY_DIR + 'apps/debug/n4w1_mock.py'] if not N4W1 else []
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/debug/*.py', exclude=exclude_n4w1))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/homescreen/*.py',
exclude=[
@@ -876,6 +882,7 @@ if FROZEN:
ui_layout=ui.get_ui_layout(TREZOR_MODEL),
thp=THP,
power_manager='power_manager' in FEATURES_AVAILABLE,
+ n4w1=N4W1,
include_source_lines=MICROPY_ENABLE_SOURCE_LINE,
)
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index 8c46472f..31170e5c 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -56,6 +56,7 @@ tropic = []
serial_number = []
storage = []
telemetry = []
+n4w1 = []
translations = ["crypto"]
secmon_layout = []
dbg_console = []
diff --git a/core/embed/upymod/modtrezorutils/modtrezorutils.c b/core/embed/upymod/modtrezorutils/modtrezorutils.c
index ca1b643b..119fac04 100644
--- a/core/embed/upymod/modtrezorutils/modtrezorutils.c
+++ b/core/embed/upymod/modtrezorutils/modtrezorutils.c
@@ -798,6 +798,8 @@ STATIC const mp_obj_tuple_t mod_trezorutils_version_obj = {
/// """Whether the firmware supports loading 3rd-party applications."""
/// USE_TELEMETRY: bool
/// """Whether a telemetry is supported."""
+/// USE_N4W1: bool
+/// """Whether N4W1 is supported."""
/// MODEL: str
/// """Model name."""
/// MODEL_FULL_NAME: str
@@ -909,6 +911,11 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else
{MP_ROM_QSTR(MP_QSTR_USE_SERIAL_NUMBER), mp_const_false},
#endif
+#if USE_N4W1
+ {MP_ROM_QSTR(MP_QSTR_USE_N4W1), mp_const_true},
+#else
+ {MP_ROM_QSTR(MP_QSTR_USE_N4W1), mp_const_false},
+#endif
#if !PYOPT
#if LOG_STACK_USAGE
{MP_ROM_QSTR(MP_QSTR_zero_unused_stack),
diff --git a/core/mocks/generated/trezorutils.pyi b/core/mocks/generated/trezorutils.pyi
index 29c48f8c..d2d6ada4 100644
--- a/core/mocks/generated/trezorutils.pyi
+++ b/core/mocks/generated/trezorutils.pyi
@@ -280,6 +280,8 @@ USE_APP_LOADING: bool
"""Whether the firmware supports loading 3rd-party applications."""
USE_TELEMETRY: bool
"""Whether a telemetry is supported."""
+USE_N4W1: bool
+"""Whether N4W1 is supported."""
MODEL: str
"""Model name."""
MODEL_FULL_NAME: str
diff --git a/core/site_scons/models/T3W1/emulator.py b/core/site_scons/models/T3W1/emulator.py
index c15f1de4..171b2d76 100644
--- a/core/site_scons/models/T3W1/emulator.py
+++ b/core/site_scons/models/T3W1/emulator.py
@@ -159,4 +159,8 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
+ if "n4w1" in features_wanted:
+ defines += [("USE_N4W1", "1")]
+ features_available.append("n4w1")
+
return features_available
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
index 117cbed7..f9728c5b 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
@@ -319,6 +319,10 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
+ if "n4w1" in features_wanted:
+ defines += [("USE_N4W1", "1")]
+ features_available.append("n4w1")
+
ENV["LINKER_SCRIPT"] = linker_script
ENV["MEMORY_LAYOUT"] = memory_layout
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
index fcd4e756..8b99c0e7 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
@@ -333,6 +333,10 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
+ if "n4w1" in features_wanted:
+ defines += [("USE_N4W1", "1")]
+ features_available.append("n4w1")
+
ENV["LINKER_SCRIPT"] = linker_script
ENV["MEMORY_LAYOUT"] = memory_layout
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
index 372ac661..30f0113b 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
@@ -331,6 +331,10 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
+ if "n4w1" in features_wanted:
+ defines += [("USE_N4W1", "1")]
+ features_available.append("n4w1")
+
ENV["LINKER_SCRIPT"] = linker_script
ENV["MEMORY_LAYOUT"] = memory_layout
diff --git a/core/site_scons/site_tools/micropython/__init__.py b/core/site_scons/site_tools/micropython/__init__.py
index c05da6aa..df89d0a2 100644
--- a/core/site_scons/site_tools/micropython/__init__.py
+++ b/core/site_scons/site_tools/micropython/__init__.py
@@ -62,6 +62,7 @@ def generate(env):
layout_eckhart = env["ui_layout"] == "UI_LAYOUT_ECKHART"
thp = env["thp"]
power_manager = env["power_manager"]
+ n4w1 = env["n4w1"]
include_source_lines = env["include_source_lines"]
interim = f"{target[:-4]}.i" # replace .mpy with .i
sed_scripts = [
@@ -78,6 +79,7 @@ def generate(env):
rf"-e 's/utils\.USE_TOUCH/{touch}/g'",
rf"-e 's/utils\.USE_THP/{thp}/g'",
rf"-e 's/utils\.USE_POWER_MANAGER/{power_manager}/g'",
+ rf"-e 's/utils\.USE_N4W1/{n4w1}/g'",
r"-e 's/if TYPE_CHECKING/if False/'",
r"-e 's/import typing/# &/'",
r"-e '/from typing import (/,/^[[:space:]]*)/ {s/^/# /; }'",
diff --git a/core/src/apps/debug/__init__.py b/core/src/apps/debug/__init__.py
index fcae69e1..fc31fabe 100644
--- a/core/src/apps/debug/__init__.py
+++ b/core/src/apps/debug/__init__.py
@@ -448,7 +448,7 @@ if __debug__:
finally:
raise RestartEventLoop
- if utils.INTERNAL_MODEL == "T3W1": # TODO utils.USE_N4W1
+ if utils.USE_N4W1:
async def dispatch_DebugLinkConnected(msg: DebugLinkN4W1Connected) -> Success:
"""Exchange a sequence of N4W1 messages."""
@@ -577,7 +577,7 @@ if __debug__:
MessageType.WipeDevice: dispatch_WipeDevice,
}
- if utils.INTERNAL_MODEL == "T3W1": # TODO utils.USE_N4W1
+ if utils.USE_N4W1:
WORKFLOW_HANDLERS[MessageType.DebugLinkN4W1Connected] = (
dispatch_DebugLinkConnected
)
diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py
index 6a495f2e..f416e763 100644
--- a/core/src/trezor/utils.py
+++ b/core/src/trezor/utils.py
@@ -27,6 +27,7 @@ from trezorutils import ( # noqa: F401
USE_BUTTON,
USE_DBG_CONSOLE,
USE_HAPTIC,
+ USE_N4W1,
USE_NRF,
USE_OPTIGA,
USE_POWER_MANAGER,
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.