feature: integrate 7.14.1 firmware updates#424
Closed
BitHighlander wants to merge 50 commits into
Closed
Conversation
Adds an in-process emulator library (libkkemu, .dylib on macOS / .so on
linux) so a host process can drive firmware logic via FFI instead of
spinning up a separate kkemu binary and talking over UDP. Used by vault
v11 to host the emulator inside the Bun process for the wallet onboarding
+ Zcash testing flows; also lets researchers fuzz / drive firmware
behavior from arbitrary host code without the network hop.
Build:
cmake -DKK_EMULATOR=1 -DKK_BUILD_DYLIB=1 -B build-emu .
cmake --build build-emu --target kkemulator_dylib
The standalone `kkemu` UDP-driven binary continues to build with
KK_EMULATOR=1 alone, byte-identical to before.
Files:
- include/keepkey/emulator/libkkemu.h, lib/emulator/libkkemu.c
C API exposed to host: init(seed), step(), screenshot capture
(display_refresh frames packed 8bpp->1bpp into a 256x64x1 buffer),
ringbuf-backed message I/O.
- lib/emulator/ringbuf.{c,h}
Lock-free single-producer/single-consumer byte ring used by
libkkemu's host I/O paths (replaces the UDP sockets in dylib mode).
- lib/emulator/setup.c
setup_urandom_only() — RNG init for libkkemu callers that
provide their own flash buffer (no flash mmap).
- lib/emulator/udp.c
Behind #ifdef KKEMU_DYLIB: emulatorSocketInit/Read/Write become
thin trampolines to the libkkemu ring buffers. Standalone build is
unchanged. Adds optional KEEPKEY_UDP_PORT env override for the
kkemu binary so multiple emulators can share a host.
- lib/emulator/CMakeLists.txt, tools/emulator/CMakeLists.txt
Define the kkemulator_dylib target and refactor kkemu's link
command to share FIRMWARE_LIBS between standalone and dylib builds.
- CMakeLists.txt
cmake_policy(SET CMP0079 NEW) — required so tools/emulator can
link kkemulator_dylib which is defined in lib/emulator. KK_BUILD_DYLIB
option (default OFF) guards the whole dylib path; absent the flag,
the build is identical to fork develop.
- include/keepkey/emulator/setup.h
Forward decl for setup_urandom_only.
Out of scope (separate concerns even though they touch nearby files):
- Version bump 7.14.0 -> 7.15.0
- BITCOIN_ONLY define (BTC-only firmware variant)
- DebugLink screenshot canvas semantics (next commit)
- CI screenshot pipeline / zoo workflows
…t capture
fsm_msgDebugLinkGetState previously called force_animation_start() +
animate() before capturing the canvas (or wrapped both in
`if (is_animating())`). Both forms produce the same bug for non-animated
screens (warning_static, address displays, etc.):
- The confirm() loop already calls animate() before sending the
ButtonRequest that triggers DebugLinkGetState.
- When the layout is static (no animation queued) and we still call
force_animation_start() + animate() in the DebugLink handler, we
overwrite the static canvas with a stale animation frame OR a no-op,
depending on queue state — either way, the screenshot the host
captures is not what the user is actually seeing.
Replace with a single display_refresh() call. The canvas already holds
the right pixels by the time DebugLinkGetState fires; we just need the
framebuffer synced before the host reads it.
Production firmware (compiled with KK_DEBUG_LINK=0) is unaffected — the
function is excluded from non-debug builds entirely.
Was the missing piece for the CI screenshot pipeline correctly capturing
warning + confirmation screens with their as-rendered text instead of
animation frames or empty buffers.
… response Bumps RINGBUF_CAPACITY from 32 to 128. The previous value left effective room for 31 HID reports between writer and reader; DebugLinkGetState now serializes a 2048-byte `layout` plus the rest of DebugLinkState (~2.7 KB total payload, ~44 reports after the per-report sync prefix + continuation byte). Pushes past slot 31 returned 0 from emulatorSocketWrite(), but upstream lib/board/usb.c::msg_debug_write() ignores the return — so the host saw a silently-truncated screenshot capture instead of a clean failure. 128 gives ~3x headroom on the worst current response, accommodates DebugLinkFlashDumpResponse (1024-byte chunks) plus future field growth, and stays a power of two so the modulo in ringbuf_push/pop is a cheap mask. Memory cost: 4 rings × 128 × 64 = 32 KB. Trivial next to the existing 128 KB frame_ring. Out of scope: making msg_debug_write() propagate emulatorSocketWrite() failures is the right long-term fix and belongs in a separate PR (it's upstream code, not introduced by libkkemu). Until then, sizing the ring so it never overflows on a legitimate response is the pragmatic guard.
…ILD_DYLIB The previous CMakeLists.txt only marked kkemulator_dylib itself as PIC, but it links static archives (kkfirmware, kkboard, kkrand, kktransport, trezorcrypto, qrcodegenerator, SecAESSTM32, kkemulator, kkvariant.*) defined in sibling directories. macOS happens to be lenient and produces a working .dylib regardless, but Linux's link step against a non-PIC archive fails with "recompile with -fPIC". Set CMAKE_POSITION_INDEPENDENT_CODE=ON globally when KK_BUILD_DYLIB is on, BEFORE add_subdirectory(lib) below — every static target picks it up at definition time. CMP0079 (already set above) lets the dylib reach across directories to link them. When KK_BUILD_DYLIB=0 (the default), nothing changes — static libs build without -fPIC as before.
…down
Two related hardening changes in libkkemu's lifecycle:
1. mlock() failure logged
kkemu_init() previously called mlock() on the host flash buffer and
ignored the return. Many platforms cap unprivileged mlock at a few MB
(RLIMIT_MEMLOCK), and silent failure means the seed / FVK / PIN
derivation state in the buffer can be swapped to disk without anyone
knowing.
Now we check the return and log to stderr on failure ("flash buffer
may be swapped to disk; do not load production secrets"). Init still
succeeds — a dev/CI environment that hits the rlimit shouldn't be
blocked from running the emulator. Production hosts of libkkemu are
expected to treat the logged failure as a security warning and refuse
to load secrets.
2. Zero sensitive static buffers on kkemu_shutdown()
In dylib mode the library lives inside a long-running host process
(e.g. the Bun runtime in vault). Static rings, the frame ring, the
last-packed dedup buffer, and the display-pack scratch all have
static storage duration — they outlive the emulator session and are
visible to the host's memory image (core dumps, ptrace, GC roots).
They retain:
- rb_main_*: PIN, passphrase, signing inputs/outputs
- rb_debug_*: mnemonic + recovery-cipher state in DEBUG_LINK builds
- frame_ring + last_packed + display_packed_scratch: rendered OLED
bytes including PIN matrix, recovery words, address confirms,
signing summaries
Promoted the previously function-static `packed[2048]` in
kkemu_get_display() to a file-scope `display_packed_scratch` so
shutdown can reach it. All five buffers now go through trezor-crypto's
memzero() (compiler-can't-optimize-out) before munlock — the same
primitive the firmware uses everywhere it clears key material.
The host-owned flash buffer is still left for the caller to zero
(documented contract — host may want post-mortem inspection).
Bumps deps/python-keepkey to bithighlander/master 73f2a2d (the merge commit of BitHighlander/python-keepkey#14), which adds the DylibTransport for in-process libkkemu testing plus four screenshot regression tests targeting this PR's own changes: - test_layout_round_trip_fits_through_ring → covers RINGBUF_CAPACITY - test_layout_repeated_reads_no_truncation - test_layout_stable_across_idle_reads → covers fsm_msg_debug animate→display_refresh - test_layout_features_dont_corrupt_capture → iface separation Adds a new CI job, python-dylib-tests, that builds libkkemu natively (NOT in the existing Docker emulator image — different artifact, different toolchain) and runs the four tests against it. Joins publish-emulator's gate so a Docker push can't ship without the dylib path being green. Pinned tooling (matches the firmware's own .python-version + the .proto generator the repo uses): Python 3.10, protobuf 3.20.3, nanopb 0.3.9.4.post3, protoc 3.21.12 KK_DEBUG_LINK=ON at cmake time (default OFF — without it, fsm_msgDebugLinkGetState is excluded and read_layout() hangs). generate-test-report's needs list is intentionally NOT updated — that job's PDF aggregation only knows about the existing JUnit + screenshot schema. The dylib JUnit uploads as its own artifact instead. Folding into the report is a follow-up.
The first python-dylib-tests run failed in 20s on the protoc download:
unzip reported "End-of-central-directory signature not found" because
the URL 404'd and curl wrote the HTML error page to /tmp/protoc.zip.
Root cause: protobuf renamed releases from v3.21.x → v21.x at this
release ("protoc version reset" — the project decoupled protoc's
version from the C++ runtime's). The tag is `v21.12`, not `v3.21.12`,
and the file inside is `protoc-21.12-linux-x86_64.zip`, not
`protoc-3.21.12-...`.
Also added `curl -f` so the next typo fails the step on the HTTP error
instead of letting unzip belly-flop on a 404 page, plus a `file`
sanity-check on the downloaded archive.
Top-level CMakeLists.txt requires googletest unconditionally — the add_subdirectory(deps/googletest) call runs at configure time, before any target selection. Even though we only build kkemulator_dylib, configure fails with 'googletest missing' if the submodule isn't init'd. Caught by the second CI run on PR #217: protoc URL fix landed (config got past stage 1 of cmake), then died on the gtest check at line 57.
Pip-installed nanopb 0.3.9.4.post3 ships nanopb.proto + plugin.proto but NOT the generated nanopb_pb2.py / plugin_pb2.py files. Without them, nanopb_generator.py fails at import with: ImportError: attempted relative import with no known parent package at line 37 (`from .proto import nanopb_pb2, plugin_pb2`). The fix is to regenerate them — but with the PINNED protoc 3.21, NOT the github-runner's system protoc (which is too new and produces .pb2 files that require a protobuf runtime newer than the 3.20.3 we pinned, manifesting as 'Descriptors cannot be created directly'). Same trap I hit locally before this CI work landed; documented inline so the next person doesn't have to rediscover it.
…tor/) Two failures from the third dylib CI run: 1. ModuleNotFoundError: requests ethereum_tokens.def build step fetches token lists at compile time via Python; needs requests pip-installed. 2. ImportError: attempted relative import with no known parent package The protoc-gen-nanopb that protoc was finding via PATH was the COPY in <site-packages>/nanopb/generator/ — a raw .py file that fails when invoked as a top-level script. The pip install's console-script wrapper at <pyenv>/bin/protoc-gen-nanopb loads nanopb_generator as a module, so relative imports resolve. The previous PATH override prepended the broken generator/ dir ahead of bin/. Removed both PATH manipulations — setup-python already puts the python bin dir on PATH, which is where the working wrapper lives. Added `which protoc-gen-nanopb` to surface the resolved path in CI logs for any future debugging. The pb2 regeneration step still runs (the *_pb2.py files don't ship with the pip install), but the regenerated files now get loaded via the correct module path.
cmake CMakeLists.txt:78 does find_program for nanopb_generator.py
(specifically with the .py extension), which only exists in the pip
package's <site-packages>/nanopb/generator/ directory — not in the
console-script bin/ dir.
Last fix removed generator/ from PATH entirely to avoid its broken
protoc-gen-nanopb winning over the working bin/ wrapper. That flipped
the failure: cmake configure now reports 'Must install nanopb 0.3.9.4,
and put nanopb-nanopb-0.3.9.4/generator on your PATH'.
Right answer: APPEND generator/ to PATH, so:
- bin/ comes first → bin/protoc-gen-nanopb (working wrapper) wins
- generator/ comes last → only place nanopb_generator.py exists,
cmake's find_program resolves it there
Added `which protoc-gen-nanopb` and `which nanopb_generator.py` to
the configure step so future CI logs make the resolution unambiguous.
Linux build hits a duplicate-symbol link error: __stack_chk_guard is defined by both lib/board/keepkey_board.c (uintptr_t) and lib/emulator/setup.c (uint32_t). Apple's linker silently picks one (matches local macos arm64 builds that work); GNU ld is strict and fails with 'multiple definition'. Fixing requires deduping the symbol — out of scope for the current PR which is about the libkkemu runtime + screenshot tests, not the firmware's stack-canary plumbing. This commit: - runs-on: ubuntu-latest → macos-latest (arm64) - protoc download URL: linux-x86_64 → osx-aarch_64 - drops apt-get install (macos pre-installs cmake + clang) - replaces nproc with sysctl -n hw.ncpu - find prefers libkkemu.dylib, .so as fallback for future cross-plat - added inline comment + TODO documenting the Linux follow-up Once the __stack_chk_guard symbol is deduped (likely just remove emulator/setup.c's redefinition since lib/board's already provides the on-device version that emulator inherits), this job can flip back to a matrix that runs both ubuntu-latest + macos-latest.
Job hit "No module named pytest" on macos runner. The existing python-integration-tests job runs in a Docker image with pytest baked in; this new dylib job is on a vanilla macos-latest runner so it needs explicit install. Pin pytest-timeout too — even though it can't actually break the dylib's C busy-loop (per the long rationale in test_dylib_confirm_flow.py's @unittest.skip), it's used transitively by some pytest features.
The build step was producing libkkemu.dylib but only test results were
being uploaded. Add an upload-artifact step so reviewers / vault devs /
external auditors can download the dylib straight from the PR's CI run
without rebuilding the toolchain locally.
Artifact name: libkkemu-<full-sha> (avoids overwrite across PR pushes)
Path: env DYLIB_PATH (set by the build step)
Retention: 30 days
Trigger: always() so a downstream test failure doesn't lose
the binary that just built successfully
if-no-files-found: error catches a future build-step regression that
silently drops the artifact.
…ccess-list fix(eth): hash EIP-1559 access list AFTER all data chunks
Repoint deps/python-keepkey from upstream keepkey/python-keepkey to the BitHighlander fork. Fork master is now a strict superset of upstream master: upstream/master (a6c6602) + feat(transport): add DylibTransport for in-process libkkemu testing + test(dylib): screenshot regression for ringbuf capacity + canvas semantics + fix(dylib): address PR #14 review DylibTransport enables in-process testing against libkkemu without an external transport, used by upcoming integration tests. CI on the firmware fork will pull from BitHighlander/python-keepkey going forward.
chore(deps): pin python-keepkey to fork master
… proto Bumps deps/device-protocol to BitHighlander/device-protocol@feat/message-signing-parity which adds (among others) TronSignMessage / TronMessageSignature / TronVerifyMessage proto definitions used by the next commit. Per the existing fork pattern (cf. deps/python-keepkey), submodule URL is switched from upstream to the BitHighlander fork so the new branch is fetchable. Kept on a fork branch until firmware integration is validated; upstream device-protocol PR will follow.
Implements TIP-191 personal_sign for TRON, mirroring the Ethereum
implementation in lib/firmware/ethereum.c — only the prefix differs:
hash = keccak256("\x19TRON Signed Message:\n" || ASCII(len) || message)
The signature shape is identical to Ethereum's: 65 bytes (r || s || v)
where v = 27 + recovery_id, secp256k1 over the keccak digest.
Adds:
- tron_message_sign() / tron_message_verify() in tron.c
- fsm_msgTronSignMessage() / fsm_msgTronVerifyMessage() in fsm_msg_tron.h
- MSG_IN/MSG_OUT entries in messagemap.def
UX:
- Sign: PIN check, path validation (m/44'/195'/...), printable/hex display
on the OLED (truncated to 38×3 chars), user confirm before signing.
- Verify: address + signature recovered host-style, confirms signer
address then displays the verified message. Returns Success or Failure.
Verification recovers the secp256k1 pubkey from (sig, hash), derives the
canonical TRON address (keccak256 of uncompressed pubkey, last 20 bytes,
prefixed with 0x41, Base58Check-encoded), and compares against the claim.
The TIP-712 typed-data signing variant (TronSignTypedHash, IDs 1407/1408)
is left for a follow-up PR.
Fork device-protocol master was just synced with upstream (PR-equivalent merge of keepkey/master into BitHighlander/master) and then absorbed the feat/message-signing-parity branch via a no-ff merge. Bumps submodule pin to fork master tip (e0bf5a4) so this branch tracks the canonical fork state. Also switches the .gitmodules tracking branch from feat/message-signing-parity to master — that branch is now folded into master and no longer needs separate tracking.
The ecdsa_sign_digest() canonical-check contract: non-zero = accept,
zero = retry with fresh nonce. The previous implementation returned 0
unconditionally, which caused ecdsa_sign_digest to retry forever and
ultimately fail every TronSignMessage request.
Match ethereum_is_canonic exactly: return (v & 2) == 0, which accepts
v in {0, 1} and rejects v in {2, 3}. Verifiers across the TRON/EVM
ecosystem expect v in {0,1,27,28}; restricting to canonical recovery
IDs at the producer side avoids interop issues.
Reported in PR #221 review.
…ning tests Pins deps/python-keepkey to BitHighlander/python-keepkey@feat/tron-signmessage (ca1063eb), which adds: - Regenerated proto bindings from device-protocol fork master (incl. TronSignMessage/MessageSignature/VerifyMessage/SignTypedHash IDs) - tron_sign_message() / tron_verify_message() client methods - tests/test_msg_tron_signmessage.py with round-trip + rejection cases This wires up the test suite that exercises the TIP-191 implementation introduced in this PR.
Three line-wrap adjustments to satisfy lint-format CI gate: - tron.c: ecdsa_recover_pub_from_sig argument wrapping - fsm_msg_tron.h: TRON_MSG_DISPLAY_MAX macro continuation - fsm_msg_tron.h: fsm_sendFailure line break No semantic changes.
Bumps deps/device-protocol to BitHighlander/device-protocol@master (e0bf5a4), which contains TronSignTypedHash / TronTypedDataSignature (IDs 1407/1408) proto definitions used by the next commit.
Implements TIP-712 typed-data signing via the host-pre-hashed mode,
mirroring EthereumSignTypedHash exactly — TIP-712 uses the identical
'\x19\x01' prefix as EIP-712:
digest = keccak256('\x19\x01' || domain_separator_hash || message_hash)
sig = secp256k1_sign(digest) → 65 bytes (r || s || 27+v)
The host computes domain + message hashes per the TIP-712 spec; the
device assembles the digest, displays both hashes for user confirmation
on the OLED, and signs.
Adds:
- tron_typed_hash() / tron_typed_hash_sign() in tron.c
- fsm_msgTronSignTypedHash() in fsm_msg_tron.h
- MSG_IN/MSG_OUT entries in messagemap.def
UX (mirrors fsm_msgEthereumSignTypedHash):
- Confirm Base58Check signer address
- Confirm 64-char hex domain separator hash
- Confirm 64-char hex message hash (or 'No message' for domain-only typed data)
Out of scope: full on-device typed-data walker (Tron712TypesValues
analog of Ethereum712TypesValues). Hash mode covers the dapp use case
where the host renders the typed data; full mode would let the device
walk the JSON and is significantly more work — separate PR if needed.
Bumps deps/device-protocol to BitHighlander/device-protocol@master (e0bf5a4), which contains TonSignMessage / TonMessageSignature (IDs 1504/1505) used by the next commit.
Implements TON arbitrary-message Ed25519 signing. The handler fences
behind storage_isPolicyEnabled('AdvancedMode'), mirroring the
SolanaSignMessage pattern in fsm_msg_solana.h:461 — bare Ed25519 over
message bytes lacks domain separation and is indistinguishable on the
wire from a signed transaction.
The proper domain-separated path is TON Connect's ton_proof envelope,
which deserves its own proto + handler. This primitive exists so dapps
that already drive TonSignMessage on Trezor / Ledger have parity here,
but the policy gate blocks naive use.
Adds:
- ton_message_sign() in lib/firmware/ton.c (raw ed25519_sign over
msg->message; returns signature + Ed25519 public_key)
- fsm_msgTonSignMessage() in fsm_msg_ton.h with:
* PIN check, path validation (m/44'/607'/...)
* AdvancedMode policy gate
* Printable text vs hex preview confirm dialog (mirrors Solana)
- MSG_IN/MSG_OUT entries in messagemap.def
UX:
- AdvancedMode disabled → review banner + Failure_ActionCancelled
- AdvancedMode enabled → 'Sign TON Message' (printable) or
'Sign TON Bytes' (hex preview, truncated to 32 bytes + length suffix)
…nMessage proto Bumps deps/device-protocol to BitHighlander/device-protocol@master (e0bf5a4), which contains SolanaSignOffchainMessage / SolanaOffchainMessageSignature (IDs 756/757) used by the next commit.
Implements the Solana off-chain message spec (https://docs.solana.com/wallet-guide/sign-offchain-message). Device signs over: '\xff' || 'solana offchain' || version:u8 || format:u8 || length:u16 LE || message bytes The 0xFF lead byte is invalid as a Solana transaction prefix, providing the domain separation that bare SolanaSignMessage (754/755) lacks. Per fsm_msg_solana.h:461 the existing SignMessage path is gated behind the AdvancedMode policy because of that gap; this primitive carries its own domain separator, so NO AdvancedMode gate is required. Adds: - solana_offchain_message_sign() in lib/firmware/solana.c (envelope construction + Ed25519 sign, allocates 1232-byte stack buffer worst case) - fsm_msgSolanaSignOffchainMessage() in fsm_msg_solana.h with: * PIN check, path warning for non-standard derivation * Format validation (0=ASCII, 1=UTF-8 limited; format 2 rejected) * Version validation (only 0 defined) * Length validation (1212-byte spec ceiling) * Printable text vs hex preview confirm dialog - MSG_IN/MSG_OUT entries in messagemap.def Format support: - 0 = restricted ASCII (printable-only) — fully renderable on OLED - 1 = UTF-8 limited — printable bytes render, non-printable falls through to hex preview - 2 = UTF-8 extended (Ledger-only blind sign) — explicitly rejected; device requires renderable content. Out of scope: deprecating bare SolanaSignMessage. Once dapps migrate to the offchain envelope, the AdvancedMode gate on SignMessage can be tightened further or the handler removed entirely. Separate PR.
The firmware build copies .options from include/keepkey/transport/ —
NOT from the device-protocol submodule. After bumping the submodule to
fork master (which adds TIP-191/TIP-712/TON SignMessage/Solana offchain
protos), nanopb saw new bytes/string/repeated fields with no max_size
caps and emitted them as pb_callback_t. The transport sanity check
('! grep -r pb_callback_t' in lib/transport/CMakeLists.txt) failed the
build.
Adds local options entries covering every new field across all four
chains. Each PR pins to the same fork master (e0bf5a4) so all four
chains' protos are generated even when a given PR only adds firmware
code for one — the options additions must be the union.
Verified locally with kktech/firmware:v15 — make kktransport.pb passes.
The firmware build copies .options from include/keepkey/transport/ —
NOT from the device-protocol submodule. After bumping the submodule to
fork master (which adds TIP-191/TIP-712/TON SignMessage/Solana offchain
protos), nanopb saw new bytes/string/repeated fields with no max_size
caps and emitted them as pb_callback_t. The transport sanity check
('! grep -r pb_callback_t' in lib/transport/CMakeLists.txt) failed the
build.
Adds local options entries covering every new field across all four
chains. Each PR pins to the same fork master (e0bf5a4) so all four
chains' protos are generated even when a given PR only adds firmware
code for one — the options additions must be the union.
Verified locally with kktech/firmware:v15 — make kktransport.pb passes.
The firmware build copies .options from include/keepkey/transport/ —
NOT from the device-protocol submodule. After bumping the submodule to
fork master (which adds TIP-191/TIP-712/TON SignMessage/Solana offchain
protos), nanopb saw new bytes/string/repeated fields with no max_size
caps and emitted them as pb_callback_t. The transport sanity check
('! grep -r pb_callback_t' in lib/transport/CMakeLists.txt) failed the
build.
Adds local options entries covering every new field across all four
chains. Each PR pins to the same fork master (e0bf5a4) so all four
chains' protos are generated even when a given PR only adds firmware
code for one — the options additions must be the union.
Verified locally with kktech/firmware:v15 — make kktransport.pb passes.
The firmware build copies .options from include/keepkey/transport/ —
NOT from the device-protocol submodule. After bumping the submodule to
fork master (which adds TIP-191/TIP-712/TON SignMessage/Solana offchain
protos), nanopb saw new bytes/string/repeated fields with no max_size
caps and emitted them as pb_callback_t. The transport sanity check
('! grep -r pb_callback_t' in lib/transport/CMakeLists.txt) failed the
build.
Adds local options entries covering every new field across all four
chains. Each PR pins to the same fork master (e0bf5a4) so all four
chains' protos are generated even when a given PR only adds firmware
code for one — the options additions must be the union.
Verified locally with kktech/firmware:v15 — make kktransport.pb passes.
messagemap.def is included by translation units that don't see fsm_msg_tron.h (which is only #include'd from fsm.c). Without forward decls in fsm.h, the MSG_IN entries referencing fsm_msgTronSignMessage / fsm_msgTronVerifyMessage trigger 'undeclared here (not in a function)' errors at -Werror. Mirrors the existing pattern for fsm_msgTronSignTx / fsm_msgSolanaSignMessage (fsm.h:122,127). Verified locally: kkfirmware target builds clean.
messagemap.def is included by translation units that don't see fsm_msg_tron.h. Without a forward decl in fsm.h, the MSG_IN entry triggers 'fsm_msgTronSignTypedHash undeclared' at -Werror. Mirrors fsm.h:122 pattern.
messagemap.def is included by translation units that don't see fsm_msg_ton.h. Without a forward decl in fsm.h, the MSG_IN entry triggers 'fsm_msgTonSignMessage undeclared' at -Werror. Mirrors fsm.h:124 pattern.
messagemap.def is included by translation units that don't see fsm_msg_solana.h. Without a forward decl in fsm.h, the MSG_IN entry triggers 'fsm_msgSolanaSignOffchainMessage undeclared' at -Werror. Mirrors fsm.h:127 pattern.
Pulls in scripts/generate-test-report.py SECTIONS additions for the message-signing parity work, plus client methods + tests for all four chains (T6-T18 TRON, N8-N13 TON, S13-S19 Solana). Adds KK_BUILD_LABEL env to the test-report job so per-PR PDFs are no longer byte-identical. Addresses 5 issues found in the previous CI test reports: 1. New tests silently absent (no SECTIONS entry) — fixed 2. PR PDFs byte-identical — KK_BUILD_LABEL fixes 3. Firmware version stuck at 7.14.0 — partially fixed via build label 4. SECTIONS hardcoded inventory — entries added for new tests 5. Section descriptions stale — TRON/TON/Solana descriptions updated
Pulls in scripts/generate-test-report.py SECTIONS additions for the message-signing parity work, plus client methods + tests for all four chains (T6-T18 TRON, N8-N13 TON, S13-S19 Solana). Adds KK_BUILD_LABEL env to the test-report job so per-PR PDFs are no longer byte-identical. Addresses 5 issues found in the previous CI test reports: 1. New tests silently absent (no SECTIONS entry) — fixed 2. PR PDFs byte-identical — KK_BUILD_LABEL fixes 3. Firmware version stuck at 7.14.0 — partially fixed via build label 4. SECTIONS hardcoded inventory — entries added for new tests 5. Section descriptions stale — TRON/TON/Solana descriptions updated
Pulls in scripts/generate-test-report.py SECTIONS additions for the message-signing parity work, plus client methods + tests for all four chains (T6-T18 TRON, N8-N13 TON, S13-S19 Solana). Adds KK_BUILD_LABEL env to the test-report job so per-PR PDFs are no longer byte-identical. Addresses 5 issues found in the previous CI test reports: 1. New tests silently absent (no SECTIONS entry) — fixed 2. PR PDFs byte-identical — KK_BUILD_LABEL fixes 3. Firmware version stuck at 7.14.0 — partially fixed via build label 4. SECTIONS hardcoded inventory — entries added for new tests 5. Section descriptions stale — TRON/TON/Solana descriptions updated
Pulls in scripts/generate-test-report.py SECTIONS additions for the message-signing parity work, plus client methods + tests for all four chains (T6-T18 TRON, N8-N13 TON, S13-S19 Solana). Adds KK_BUILD_LABEL env to the test-report job so per-PR PDFs are no longer byte-identical. Addresses 5 issues found in the previous CI test reports: 1. New tests silently absent (no SECTIONS entry) — fixed 2. PR PDFs byte-identical — KK_BUILD_LABEL fixes 3. Firmware version stuck at 7.14.0 — partially fixed via build label 4. SECTIONS hardcoded inventory — entries added for new tests 5. Section descriptions stale — TRON/TON/Solana descriptions updated
… build # Conflicts: # deps/python-keepkey
# Conflicts: # include/keepkey/firmware/fsm.h # include/keepkey/firmware/tron.h # lib/firmware/fsm_msg_tron.h # lib/firmware/messagemap.def # lib/firmware/tron.c
Practice release integrating: - PR #217: libkkemu shared library + native macOS build - PR #221: TRON TIP-191 SignMessage + VerifyMessage - PR #222: TRON TIP-712 SignTypedHash - PR #223: TON Ed25519 SignMessage (AdvancedMode-gated) - PR #224: Solana SignOffchainMessage (domain-separated envelope) PR #215 (CI artifact / kitchen-sink) deferred — not on critical path for this practice run. This release branch is for fork-only testing; original feature branches remain untouched for upstream PRs.
PR #217's libkkemu/* files weren't pre-formatted; my PR #222 merge resolution appended TIP-712 handler with a stray trailing line in fsm_msg_tron.h; zxappliquid.c is pre-existing debt that the strict CI gate now catches at -Werror. No semantic changes — pure formatting normalization needed to pass the lint-format CI gate on integration branches that combine multiple feature PRs.
Collaborator
Author
|
Superseded by #425, which uses the upstream keepkey/keepkey-firmware release-7141 branch into develop. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Integrates the 7.14.1 firmware work onto upstream
developfrom a non-release branch name (feature-7141) so CI does not apply release-branch behavior.Includes:
deps/device-protocolto release: device-protocol 7.14.1 message-signing sync device-protocol#103 head73ca75fdeps/python-keepkeyto release: python-keepkey 7.14.1 message-signing bindings python-keepkey#194 head7141dc8Notes:
Validation
git diff --check keepkey/develop..HEAD