Skip to content

feat: add TRON and TON chain support#387

Draft
BitHighlander wants to merge 7 commits intodevelopfrom
feat/tron-ton-support
Draft

feat: add TRON and TON chain support#387
BitHighlander wants to merge 7 commits intodevelopfrom
feat/tron-ton-support

Conversation

@BitHighlander
Copy link
Collaborator

Motivation

TRON (TRX): Top-15 chain by market cap, widely used in Asia-Pacific markets. TRON uses secp256k1 (same curve as Bitcoin/Ethereum), making the cryptographic implementation straightforward. Users holding TRC-20 tokens (especially USDT-TRC20, the most-used stablecoin transfer rail) need hardware wallet support.

TON (The Open Network): Originally developed by Telegram, TON has grown to top-10 by active addresses. It uses Ed25519 (same as Solana/Nano) but has a unique address derivation scheme based on wallet contract StateInit hashing. Adding TON expands KeepKey into the Telegram ecosystem.

Changes

TRON (tron.c, fsm_msg_tron.h):

  • secp256k1 key derivation at m/44'/195'/account'/change/index
  • Address: Base58Check-encoded with 0x41 prefix (T-address format)
  • Transaction signing: SHA256 hash of raw transaction data, ECDSA recoverable signature (65 bytes)
  • Path validation enforces 44'/195' prefix
  • Wire: TronGetAddress (1400) → TronAddress (1401), TronSignTx (1402) → TronSignedTx (1403)

TON (ton.c, fsm_msg_ton.h):

  • Ed25519 key derivation at m/44'/607'/account'/change/index
  • Address derivation uses v4r2 wallet contract StateInit hash — not a simple pubkey hash. The device computes SHA256(StateInit(v4r2_code_hash, data_cell(pubkey))) using hardcoded v4r2 wallet code cell hash (32 bytes), avoiding the need to store the full contract code on-device.
  • User-friendly address encoding with bounceable/non-bounceable flag and CRC16 checksum
  • Transaction signing: Ed25519 sign raw transaction bytes
  • Path validation enforces 44'/607' prefix
  • Wire: TonGetAddress (1500) → TonAddress (1501), TonSignTx (1502) → TonSignedTx (1503)

Code review fixes included:

  • Bounceable flag: corrected from 0x11 | 0x11 (no-op) to bounceable ? 0x11 : 0x51
  • tron_signTx / ton_signTx return bool for proper error propagation
  • BIP-44 path validation in both GetAddress and SignTx handlers
  • TonAddress response includes both user-friendly and raw format

Risk assessment

Both chains are isolated in new source files with no modifications to existing signing paths. TRON reuses the existing secp256k1/ECDSA stack. TON reuses the existing Ed25519 stack. The v4r2 address derivation uses a hardcoded 32-byte hash constant — if the v4r2 contract standard changes (unlikely, it's been stable since 2022), the constant would need updating, but the address would simply not match any deployed contract (fail-safe, not fail-dangerous).

Testing

  • TRON python tests: 3 test cases (T-prefix Base58, different accounts, deterministic)
  • TON python tests: 4 test cases (address format, different accounts, deterministic, format validation)
  • Tests skip on firmware < 7.14.0
  • ARM and emulator builds clean

- Point device-protocol and python-keepkey submodules to upstream master
  (includes BIP-85, Solana, Tron, TON wire IDs and proto definitions)
- Add nanopb .options files for Solana, Tron, TON (field size constraints)
- Add Bip85Mnemonic.mnemonic max_size:241 to messages.options
- Update lib/transport/CMakeLists.txt with new proto sources, options,
  headers, and protoc compilation commands
- Fix CI: use pre-installed clang-format instead of apt-get install
  (eliminates 3-minute timeout on GitHub runners)
- Update Zcash transparent branch ID from Sapling to NU6
@BitHighlander BitHighlander force-pushed the feat/tron-ton-support branch 2 times, most recently from 8b53910 to 1b50b34 Compare March 17, 2026 03:16
BitHighlander and others added 4 commits March 16, 2026 21:28
TRON: secp256k1 + Keccak256 address derivation, SHA256 tx signing
TON: Ed25519 address derivation with CRC16 + Base64url, Ed25519 tx signing

Both use existing trezor-crypto primitives only.
- Fix bounceable flag no-op: use ternary (0x11 vs 0x51) instead of OR
- Check ecdsa_uncompress_pubkey return value in tron_getAddress
- Add BIP44 path validation: m/44'/195'/... for Tron, m/44'/607'/... for TON
- Change signTx functions to return bool (was void, silent failures)
- Check signTx return in FSM handlers, send proper failure on error

Note: TON address derivation uses SHA-256(pubkey) which produces non-standard
addresses. Standard TON addresses require SHA-256(StateInit cell) which includes
wallet contract code — too large for firmware flash. This is a known limitation
documented for future resolution.
ton_get_address() was computing sha256(pubkey) directly, which does not
correspond to any deployable TON wallet contract. The correct TON v4r2
address is sha256(StateInit(code_cell, data_cell)) where the data cell
contains seqno=0, walletId=698983191, and the ed25519 public key.

The fix hardcodes the well-known v4r2 code cell hash and depth, computes
the data cell representation hash from the public key, then derives the
StateInit hash. This produces addresses compatible with the standard v4r2
wallet contract used by TonKeeper, MyTonWallet, and @ton/ton SDK.
@BitHighlander BitHighlander force-pushed the feat/tron-ton-support branch from 1b50b34 to 2bf5c47 Compare March 17, 2026 03:31
@BitHighlander BitHighlander force-pushed the feat/tron-ton-support branch from 40ffd80 to 65b63f5 Compare March 17, 2026 04:04
@BitHighlander BitHighlander marked this pull request as draft March 18, 2026 00:57
BitHighlander added a commit to BitHighlander/keepkey-firmware that referenced this pull request Mar 18, 2026
Security improvement: firmware reconstructs protobuf from structured
fields (TronTransferContract, TronTriggerSmartContract) and signs the
reconstruction. Display shows verified data, not host-asserted strings.

- Structured mode: host sends transfer/trigger_smart fields, firmware
  rebuilds raw_data protobuf, displays verified amount/address, signs
- Legacy mode: raw_data field still works with explicit blind-sign warning
- TRC-20 ABI decoding: recognizes transfer(address,uint256) selector
- 12 hardcoded TRC-20 tokens (USDT, USDC, SUN, BTT, etc.)
- Bounded protobuf serialization with capacity checks
- Address validation BEFORE display (prevents confusion attacks)
- C unit tests for address, TRC-20 decoding, formatting
- Device-protocol updated with structured message definitions

Based on upstream keepkey#387 (feat/tron-ton-support)
BitHighlander added a commit to BitHighlander/keepkey-firmware that referenced this pull request Mar 18, 2026
TON uses Cell/BoC encoding which cannot be parsed on embedded devices.
This commit adds the minimum viable clear-signing improvements:

- Add ton_validateAddress(): Base64 URL-safe decode + CRC16-XMODEM
  checksum verification + tag byte validation. Destination address
  is now validated BEFORE being displayed to the user.
- Add explicit "Blind Signature" warning on all TON signing paths.
  Users must acknowledge that TX details cannot be verified on-device.
- Reject invalid destination addresses with FailureType_Failure_SyntaxError
  instead of showing unvalidated data.
- C unit tests: address validation (NULL, wrong length, bad checksum,
  bad tag), round-trip generate+validate, amount formatting.

Note: Full Cell reconstruction (reconstruct-then-sign) for TON is a
future improvement. Cell/BoC bit-level encoding is too complex for
this pass. The blind-sign warning makes the security model explicit.

Based on upstream keepkey#387 (feat/tron-ton-support)
BitHighlander added a commit to BitHighlander/keepkey-firmware that referenced this pull request Mar 18, 2026
TON uses Cell/BoC encoding which cannot be parsed on embedded devices.
This commit adds the minimum viable clear-signing improvements:

- Add ton_validateAddress(): Base64 URL-safe decode + CRC16-XMODEM
  checksum verification + tag byte validation. Destination address
  is now validated BEFORE being displayed to the user.
- Add explicit "Blind Signature" warning on all TON signing paths.
  Users must acknowledge that TX details cannot be verified on-device.
- Reject invalid destination addresses with FailureType_Failure_SyntaxError
  instead of showing unvalidated data.
- C unit tests: address validation (NULL, wrong length, bad checksum,
  bad tag), round-trip generate+validate, amount formatting.

Note: Full Cell reconstruction (reconstruct-then-sign) for TON is a
future improvement. Cell/BoC bit-level encoding is too complex for
this pass. The blind-sign warning makes the security model explicit.

Based on upstream keepkey#387 (feat/tron-ton-support)
BitHighlander added a commit to BitHighlander/keepkey-firmware that referenced this pull request Mar 18, 2026
Security improvement: firmware reconstructs protobuf from structured
fields (TronTransferContract, TronTriggerSmartContract) and signs the
reconstruction. Display shows verified data, not host-asserted strings.

- Structured mode: host sends transfer/trigger_smart fields, firmware
  rebuilds raw_data protobuf, displays verified amount/address, signs
- Legacy mode: raw_data field still works with explicit blind-sign warning
- TRC-20 ABI decoding: recognizes transfer(address,uint256) selector
- 12 hardcoded TRC-20 tokens (USDT, USDC, SUN, BTT, etc.)
- Bounded protobuf serialization with capacity checks
- Address validation BEFORE display (prevents confusion attacks)
- C unit tests for address, TRC-20 decoding, formatting
- Device-protocol updated with structured message definitions

Based on upstream keepkey#387 (feat/tron-ton-support)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant