feat(nufi-tron): update check/parse/sign func
What changed, and why it matters
This commit refactors how the Keystone 3 hardware wallet handles TRON (TRX) transactions. It switches the signing pipeline from accepting a custom JSON transaction description to accepting a raw protobuf transaction, and it tightens the HD path validation. The change is mostly a feature update for NuFi TRON support, but it also removes some address-derivation checks that previously ensured the transaction's 'from' address matched the wallet's key. That removal could, in theory, make it easier for a malicious companion app to ask the device to sign a transaction that does not belong to the wallet, though the companion app still needs to pass the wallet's master fingerprint and xpub checks. There is no explicit security bug or exploit shown in the diff, but the change is security-relevant because it alters the trust boundary between the host and the device.
Review the new protobuf parsing paths for malformed contract data (e.g., out-of-bounds reads in TriggerSmartContract data slicing at indices 16..36 and 36..68), confirm that `check_tx_request` is always invoked and its result enforced before `sign_tx_request`, and verify that the master-fingerprint check in `tron_check_sign_request` cannot be bypassed by a host that supplies a matching xpub but a different derivation path. Also ensure the removed JSON parser did not provide stronger input validation than the new raw protobuf decoder.
Security signals we found
Changed transaction input format from JSON to raw protobuf, altering the parser's attack surface
Removed seed-derived address equality check in sign_tx_request
Added HD path coin-type enforcement (194'/195')
Added master-fingerprint comparison in the Rust C bridge before transaction check
Simplified check_tx_request to compare xpub-derived address against protobuf 'from' address
Removed unused imports and dead code, reducing attack surface
Evidence from the diff
The patch replaces JSON-based TRON transaction parsing/signing with protobuf-based raw transaction handling. Key changes: (1) address.rs now accepts 5- or 6-segment BIP44 paths and enforces coin type 194’ or 195’. (2) lib.rs removes the previous sign_tx_request address-derivation equality check (derived_raw_address != json_from_bytes -> NoMyInputs) and replaces check_tx_request with a simpler xpub-derived address comparison. (3) wrapped_tron.rs removes from_json_bytes and adds from_raw_transaction, decoding TransferContract, TriggerSmartContract (TRC-20), and TransferAssetContract (TRC-10) directly from protobuf. (4) rust_c/src/tron/mod.rs adds master-fingerprint comparison against the UR source fingerprint before calling check. (5) gui_trx.c removes commented-out code and no longer passes xpub to parse/check/sign helpers. The diff does not show any explicit vulnerability, but the removal of the seed-derived address check in sign_tx_request shifts responsibility for ‘is this my input’ to the check phase and the host-supplied protobuf.
Changed components
rust/apps/tron/src/address.rsrust/apps/tron/src/lib.rsrust/apps/tron/src/transaction/wrapped_tron.rsrust/rust_c/src/tron/mod.rssrc/ui/gui_chain/multi/web3/gui_trx.cInspect captured patch +199 / −337
diff --git a/rust/apps/tron/src/address.rs b/rust/apps/tron/src/address.rs
index f10c239..da56cd2 100644
--- a/rust/apps/tron/src/address.rs
+++ b/rust/apps/tron/src/address.rs
@@ -10,9 +10,16 @@ use keystore::algorithms::secp256k1::derive_public_key;
macro_rules! check_hd_path {
($t: expr) => {{
let mut result: Result<()> = Ok(());
- if $t.len() != 6 {
- result = Err(TronError::InvalidHDPath(format!("{:?}", $t)));
- };
+ if $t.len() < 5 || $t.len() > 6 {
+ result = Err(TronError::InvalidHDPath(format!("Length error: {:?}", $t)));
+ } else {
+ let coin_type_idx = if $t.len() == 6 { 2 } else { 1 };
+ let coin_type = $t[coin_type_idx];
+
+ if coin_type != "194'" && coin_type != "195'" {
+ result = Err(TronError::InvalidHDPath(format!("Coin type mismatch: {}", coin_type)));
+ }
+ }
result
}};
}
diff --git a/rust/apps/tron/src/lib.rs b/rust/apps/tron/src/lib.rs
index 232e747..9b2ae46 100644
--- a/rust/apps/tron/src/lib.rs
+++ b/rust/apps/tron/src/lib.rs
@@ -7,9 +7,7 @@ extern crate core;
extern crate std;
use crate::errors::{Result, TronError};
-use crate::utils::base58check_to_u8_slice;
use alloc::string::String;
-use alloc::vec;
use ur_registry::pb::protoc;
@@ -22,11 +20,9 @@ mod utils;
pub use crate::address::get_address;
pub use crate::transaction::parser::{DetailTx, OverviewTx, ParsedTx, TxParser};
use crate::transaction::wrapped_tron::WrappedTron;
-use crate::utils::keccak256;
use alloc::string::ToString;
+use alloc::vec::Vec;
use app_utils::keystone;
-use core::str::FromStr;
-use keystore::algorithms::secp256k1;
use transaction::checker::TxChecker;
use transaction::signer::Signer;
@@ -49,53 +45,47 @@ pub fn check_raw_tx(raw_tx: protoc::Payload, context: keystone::ParseContext) ->
tx_data.check(&context)
}
-pub fn sign_tx_request(json_bytes: &[u8], hd_path: &String, seed: &[u8]) -> errors::Result<String> {
- let tx = WrappedTron::from_json_bytes(json_bytes, hd_path.clone())?;
+fn decode_to_wrapped(sign_data: &[u8], path: String) -> Result<WrappedTron> {
+ use crate::pb::protocol::transaction::Raw as RawData;
+ use crate::pb::protocol::Transaction;
+ use prost::Message;
- let pubkey = secp256k1::get_public_key_by_seed(seed, hd_path)
- .map_err(|e| TronError::KeystoreError(e.to_string()))?;
+ let raw_content = RawData::decode(sign_data)
+ .map_err(|_| TronError::InvalidRawTxCryptoBytes("RawData decode failed".to_string()))?;
- let derived_raw_address = {
- // Get uncompressed public key (65 bytes), remove 0x04 prefix, keep 64 bytes
- let uncompressed = pubkey.serialize_uncompressed();
- let pubkey_hash_input = &uncompressed[1..65];
-
- let digest = keccak256(pubkey_hash_input);
-
- // Construct TRON address bytes: 0x41 + last 20 bytes of Keccak256 hash
- let mut raw = vec![0x41u8];
- raw.extend_from_slice(&digest[12..]);
- raw
+ let raw_tx = Transaction {
+ raw_data: Some(raw_content),
+ signature: Vec::new(),
};
- let json_from_bytes = base58check_to_u8_slice(tx.from.clone())?;
- if derived_raw_address != json_from_bytes {
- return Err(TronError::NoMyInputs);
- }
+ WrappedTron::from_raw_transaction(raw_tx, path)
+}
+
+pub fn sign_tx_request(sign_data: &[u8], hd_path: &String, seed: &[u8]) -> errors::Result<String> {
+ let tx = decode_to_wrapped(sign_data, hd_path.clone())?;
let (signed_hex, _) = tx.sign(seed)?;
Ok(signed_hex)
}
-pub fn parse_tx_request(json_bytes: &[u8], path: &String) -> errors::Result<ParsedTx> {
- let tx = WrappedTron::from_json_bytes(json_bytes, path.clone())?;
- let parsed_tx = tx.parse()?;
- Ok(parsed_tx)
+pub fn parse_tx_request(sign_data: &[u8], path: &String) -> Result<ParsedTx> {
+ let tx = decode_to_wrapped(sign_data, path.clone())?;
+ tx.parse()
}
pub fn check_tx_request(
- sign_data: &[u8],
+ sign_data: &[u8],
path: &str,
- master_fingerprint: bitcoin::bip32::Fingerprint,
- xpub: &str,
-) -> Result<()> {
- let mut tx_data = WrappedTron::from_json_bytes(sign_data, path.to_string())?;
- tx_data.extended_pubkey = xpub.to_string();
+ xpub: &str
+ ) -> errors::Result<()> {
+ let derived_address = get_address(path.to_string(), &xpub.to_string())?;
+ let tx = decode_to_wrapped(sign_data, path.to_string())?;
- let extended_pubkey = bitcoin::bip32::Xpub::from_str(xpub)
- .map_err(|_| errors::TronError::InvalidParseContext(String::from("invalid xpub")))?;
- let context = keystone::ParseContext::new(master_fingerprint, extended_pubkey);
- tx_data.check(&context)
+ if derived_address != tx.from {
+ return Err(TronError::NoMyInputs);
+ }
+
+ Ok(())
}
#[cfg(test)]
@@ -156,147 +146,17 @@ mod test {
assert!(result.is_ok());
}
- // Helper function: compute TRON address from seed and path, used for test data construction
- fn compute_address_from_seed(seed: &[u8], path: &String) -> String {
- let pubkey = secp256k1::get_public_key_by_seed(seed, path).unwrap();
- let uncompressed = pubkey.serialize_uncompressed();
- let hash = keccak256(&uncompressed[1..65]);
- let mut address_bytes = [0u8; 21];
- address_bytes[0] = 0x41;
- address_bytes[1..].copy_from_slice(&hash[12..]);
- bitcoin::base58::encode_check(&address_bytes)
- }
-
- #[test]
- fn test_sign_tx_request_success() {
- let path = "m/44'/195'/0'/0/0".to_string();
- let seed = hex::decode("5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4").unwrap();
-
- let pubkey = secp256k1::get_public_key_by_seed(&seed, &path).unwrap();
- let uncompressed = pubkey.serialize_uncompressed();
- let digest = keccak256(&uncompressed[1..65]);
- let mut raw = vec![0x41u8];
- raw.extend_from_slice(&digest[12..]);
- let correct_address = compute_address_from_seed(&seed, &path);
-
- let json_str = format!(
- r#"{{
- "token": "TRX",
- "contract_address": "",
- "from": "{}",
- "to": "{}",
- "memo": "Test Transaction",
- "value": "1000000",
- "latest_block": {{
- "hash": "000000000001e240dec2860d5e1687299b8f269d09ceea82e7b96408dab58bd2",
- "number": 123456,
- "timestamp": 1670000000
- }},
- "override": {{
- "token_short_name": "TRX",
- "token_full_name": "tron",
- "decimals": 6
- }},
- "fee": 1000000
- }}"#,
- correct_address, correct_address
- );
-
- let result = sign_tx_request(json_str.as_bytes(), &path, &seed);
- if let Err(ref e) = result {
- std::println!("Sign Error Details: {:?}", e);
- }
-
- assert!(
- result.is_ok(),
- "Sign should succeed when address matches: {:?}",
- result.err()
- );
- }
-
- #[test]
- fn test_sign_tx_request_address_mismatch() {
- let path = "m/44'/195'/0'/0/0".to_string();
- let seed = hex::decode("5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4").unwrap();
-
- let json_str = r#"{"to":"TKCsXtfKfH2d6aEaQCctybDC9uaA3MSj2h","from":"TWrongAddressHash12345678901234567890","value":"1000000"}"#;
-
- let result = sign_tx_request(json_str.as_bytes(), &path, &seed);
-
- assert!(result.is_err());
- assert!(matches!(result.unwrap_err(), TronError::NoMyInputs));
- }
-
#[test]
fn test_parse_tx_request() {
let path = "m/44'/195'/0'/0/0".to_string();
- let json_str = r#"{
- "token": "TRX",
- "contract_address": "",
- "from": "TXhtYr8nmgiSp3dY3cSfiKBjed3zN8teHS",
- "to": "TKCsXtfKfH2d6aEaQCctybDC9uaA3MSj2h",
- "memo": "Test Transaction",
- "value": "1000000",
- "latest_block": {
- "hash": "000000000001e240dec2860d5e1687299b8f269d09ceea82e7b96408dab58bd2",
- "number": 123456,
- "timestamp": 1670000000
- },
- "override": {
- "token_short_name": "TRX",
- "token_full_name": "tron",
- "decimals": 6
- },
- "fee": 1000000
-}"#;
+ let mock_pb_hex = "0a0207902208e1b9de559665c6714080c49789bb2c5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a1541ad8593979840130d222238380b080808080808081215410d292c98a5eca06c2085fff993996423cf66c93b2244a9059cbb0000000000000000000000009bbce520d984c3b95ad10cb4e32a9294e6338da300000000000000000000000000000000000000000000000000000000000f424070c0b6e087bb2c90018094ebdc03";
+ let sign_data = hex::decode(mock_pb_hex).unwrap();
+
+ let result = parse_tx_request(&sign_data, &path);
- let result = parse_tx_request(json_str.as_bytes(), &path);
- match result {
- Ok(_) => (),
- Err(e) => panic!("Transaction parse Failed with error: {:?}", e),
- }
assert!(result.is_ok());
let parsed = result.unwrap();
- assert_eq!(parsed.overview.value, "1 TRX");
- }
-
- #[test]
- fn test_check_tx_request() {
- let path = "m/44'/195'/0'/0/0";
- let xpub = "xpub6C3ndD75jvoARyqUBTvrsMZaprs2ZRF84kRTt5r9oxKQXn5oFChRRgrP2J8QhykhKACBLF2HxwAh4wccFqFsuJUBBcwyvkyqfzJU5gfn5pY";
- let master_fingerprint = bitcoin::bip32::Fingerprint::from_str("73c5da0a").unwrap();
-
- let correct_address = get_address(path.to_string(), &xpub.to_string()).unwrap();
-
- let json_str = format!(
- r#"{{
- "token": "TRX",
- "contract_address": "",
- "xfp": "73c5da0a",
- "memo": "Test Transaction",
- "from": "{}",
- "to": "TKCsXtfKfH2d6aEaQCctybDC9uaA3MSj2h",
- "value": "1000000",
- "latest_block": {{
- "hash": "000000000001e240dec2860d5e1687299b8f269d09ceea82e7b96408dab58bd2",
- "number": 123456,
- "timestamp": 1670000000
- }},
- "override": {{
- "token_short_name": "TRX",
- "token_full_name": "tron",
- "decimals": 6
- }},
- "fee": 1000000
- }}"#,
- correct_address
- );
-
- let result = check_tx_request(json_str.as_bytes(), path, master_fingerprint, xpub);
- match result {
- Ok(_) => (),
- Err(e) => panic!("Transaction Check Failed with error: {:?}", e),
- }
+ std::println!("Parsed Value: {}", parsed.overview.value);
}
}
diff --git a/rust/apps/tron/src/transaction/wrapped_tron.rs b/rust/apps/tron/src/transaction/wrapped_tron.rs
index a0eb1c9..6fc2278 100644
--- a/rust/apps/tron/src/transaction/wrapped_tron.rs
+++ b/rust/apps/tron/src/transaction/wrapped_tron.rs
@@ -10,7 +10,6 @@ use alloc::vec::Vec;
use alloc::{format, vec};
use app_utils::keystone;
use ascii::AsciiStr;
-use core::ops::Div;
use core::str::FromStr;
use cryptoxide::hashing;
use ethabi::{
@@ -54,46 +53,104 @@ macro_rules! derivation_account_path {
}};
}
-impl WrappedTron {
- pub fn from_json_bytes(json_bytes: &[u8], path: String) -> Result<Self> {
- let json_str = core::str::from_utf8(json_bytes)
- .map_err(|_| TronError::InvalidRawTxCryptoBytes("Invalid UTF-8".to_string()))?;
-
- let temp_val: serde_json::Value = serde_json::from_str(json_str)
- .map_err(|e| TronError::InvalidRawTxCryptoBytes(e.to_string()))?;
-
- let xfp = temp_val["xfp"].as_str().unwrap_or("").to_string();
-
- let tx_data: protoc::TronTx = serde_json::from_str(json_str)
- .map_err(|e| TronError::InvalidRawTxCryptoBytes(e.to_string()))?;
-
- let mut token_short_name = None;
- let mut divider = DIVIDER;
- if let Some(ov) = &tx_data.r#override {
- token_short_name = Some(ov.token_short_name.clone());
- divider = 10u64.pow(ov.decimals as u32) as f64;
- }
+const KNOWN_TOKENS: [(&str, &str, f64); 1] =
+ [("TR7NHqjeKQxGChmqiAkX65phN6kkXNGA2h", "USDT", DIVIDER)];
- // use the existing transaction construction logic
- let tron_tx: Transaction = if tx_data.contract_address.is_empty() {
- Self::build_transfer_tx(&tx_data)?
- } else {
- Self::generate_trc20_tx(&tx_data)?
+impl WrappedTron {
+ pub fn from_raw_transaction(raw_tx: Transaction, path: String) -> Result<Self> {
+ let mut instance = Self {
+ tron_tx: raw_tx,
+ hd_path: path,
+ extended_pubkey: String::new(),
+ xfp: String::new(),
+ token: "TRX".to_string(),
+ contract_address: String::new(),
+ from: String::new(),
+ to: String::new(),
+ value: "0".to_string(),
+ divider: DIVIDER,
+ token_short_name: None,
};
- Ok(Self {
- hd_path: path,
- extended_pubkey: "".to_string(), // leave empty when no context
- tron_tx,
- xfp,
- token: tx_data.token,
- contract_address: tx_data.contract_address,
- from: tx_data.from,
- to: tx_data.to,
- value: tx_data.value,
- divider,
- token_short_name,
- })
+ if let Some(raw) = &instance.tron_tx.raw_data {
+ if let Some(contract) = raw.contract.get(0) {
+ use crate::pb::protocol::transaction::contract::ContractType;
+ let c_type = ContractType::from_i32(contract.r#type)
+ .unwrap_or(ContractType::TransferContract);
+
+ if let Some(param) = &contract.parameter {
+ match c_type {
+ // A. TRX Transfer
+ ContractType::TransferContract => {
+ let ct =
+ TransferContract::decode(param.value.as_slice()).map_err(|_| {
+ TronError::InvalidRawTxCryptoBytes(
+ "TransferContract decode failed".to_string(),
+ )
+ })?;
+ instance.from = bitcoin::base58::encode_check(&ct.owner_address);
+ instance.to = bitcoin::base58::encode_check(&ct.to_address);
+ instance.value = ct.amount.to_string();
+ instance.token = "TRX".to_string();
+ instance.divider = DIVIDER;
+ }
+
+ // B. TRC-20 Transfer
+ ContractType::TriggerSmartContract => {
+ let ct = TriggerSmartContract::decode(param.value.as_slice()).map_err(
+ |_| {
+ TronError::InvalidRawTxCryptoBytes(
+ "TriggerSmartContract decode failed".to_string(),
+ )
+ },
+ )?;
+ instance.from = bitcoin::base58::encode_check(&ct.owner_address);
+ instance.contract_address =
+ bitcoin::base58::encode_check(&ct.contract_address);
+
+ if ct.data.len() >= 68 && &ct.data[0..4] == &[0xa9, 0x05, 0x9c, 0xbb] {
+ let mut to_addr_bytes = vec![0x41u8];
+ to_addr_bytes.extend_from_slice(&ct.data[16..36]);
+ instance.to = bitcoin::base58::encode_check(&to_addr_bytes);
+
+ let amount_bytes = &ct.data[36..68];
+ instance.value =
+ ethabi::ethereum_types::U256::from_big_endian(amount_bytes)
+ .to_string();
+
+ if let Some(token_info) = KNOWN_TOKENS
+ .iter()
+ .find(|t| t.0 == instance.contract_address)
+ {
+ instance.token = token_info.1.to_string();
+ instance.divider = token_info.2;
+ } else {
+ instance.token = "TRC20".to_string();
+ instance.divider = 10u64.pow(18) as f64;
+ }
+ }
+ }
+
+ // C. TRC-10 Transfer
+ ContractType::TransferAssetContract => {
+ let ct = TransferAssetContract::decode(param.value.as_slice())
+ .map_err(|_| {
+ TronError::InvalidRawTxCryptoBytes(
+ "TransferAssetContract decode failed".to_string(),
+ )
+ })?;
+ instance.from = bitcoin::base58::encode_check(&ct.owner_address);
+ instance.to = bitcoin::base58::encode_check(&ct.to_address);
+ instance.value = ct.amount.to_string();
+ instance.token = String::from_utf8_lossy(&ct.asset_name).to_string();
+ instance.divider = DIVIDER;
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ Ok(instance)
}
pub fn check_input(&self, context: &keystone::ParseContext) -> Result<()> {
@@ -353,24 +410,59 @@ impl WrappedTron {
}
pub fn format_amount(&self) -> Result<String> {
- let value = f64::from_str(self.value.as_str())?;
+ let raw_val = f64::from_str(self.value.as_str())?;
+ let amount = raw_val / self.divider;
let unit = self.format_unit()?;
- Ok(format!("{} {}", value.div(self.divider), unit))
+ let precision = match self.divider as u64 {
+ 1 => 0,
+ 1_000_000 => 6,
+ 1_000_000_000_000_000_000 => 18,
+ _ => {
+ let mut count = 0;
+ let mut d = self.divider as u64;
+ while d >= 10 {
+ d /= 10;
+ count += 1;
+ }
+ count as usize
+ }
+ };
+ let formatted = format!("{:.*}", precision, amount);
+ let trimmed = if formatted.contains('.') {
+ formatted
+ .trim_end_matches('0')
+ .trim_end_matches('.')
+ .to_string()
+ } else {
+ formatted
+ };
+
+ let final_value = if trimmed == "0" && raw_val > 0.0 {
+ format!("{:.*}", precision, amount)
+ } else {
+ trimmed
+ };
+
+ Ok(format!("{} {}", final_value, unit))
}
pub fn format_method(&self) -> Result<String> {
if !self.contract_address.is_empty() {
Ok("TRC-20 Transfer".to_string())
- } else if !self.token.is_empty() && self.token.to_uppercase() != "TRX" {
+ } else if !self.token.is_empty() && self.token != "TRX" {
Ok("TRC-10 Transfer".to_string())
} else {
Ok("TRX Transfer".to_string())
}
}
pub fn format_unit(&self) -> Result<String> {
- match self.token_short_name.to_owned() {
- Some(name) => Ok(name),
- _ => Ok("TRX".to_string()),
+ if let Some(ref name) = self.token_short_name {
+ return Ok(name.clone());
+ }
+ if !self.token.is_empty() {
+ Ok(self.token.clone())
+ } else {
+ Ok("TRX".to_string())
}
}
}
@@ -386,60 +478,6 @@ mod tests {
use alloc::string::ToString;
use bitcoin::bip32::Fingerprint;
use core::str::FromStr;
- use serde_json::json;
-
- #[test]
- fn test_from_json_bytes_success() {
- let tron_tx_json = json!({
- "token": "TRX",
- "contract_address": "",
- "from": "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH",
- "to": "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH",
- "memo": "Test Transaction",
- "value": "1000000",
- "latest_block": {
- "hash": "000000000001e240dec2860d5e1687299b8f269d09ceea82e7b96408dab58bd2",
- "number": 123456,
- "timestamp": 1670000000
- },
- "override": {
- "token_short_name": "TRX",
- "token_full_name": "tron",
- "decimals": 6
- },
- "fee": 1000000
- });
- let json_bytes = serde_json::to_vec(&tron_tx_json).unwrap();
- let path = "m/44'/195'/0'/0/0".to_string();
- let result = WrappedTron::from_json_bytes(&json_bytes, path.clone());
- // println!("RAW ADDRESS FROM JSON: [{}]", result.as_ref().map(|tx| tx.from.clone()).unwrap_or("None".to_string()));
- if let Err(e) = &result {
- std::eprintln!("Error detail: {:?}", e);
- }
- assert!(result.is_ok());
- let tx = result.unwrap();
- assert_eq!(tx.hd_path, path);
- assert_eq!(tx.token, "TRX");
- assert_eq!(tx.value, "1000000");
- assert_eq!(tx.from, "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH");
- assert_eq!(tx.to, "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH");
- }
-
- #[test]
- fn test_from_json_bytes_invalid_utf8() {
- let invalid_bytes = vec![0xFF, 0xFF, 0xFF];
- let path = "m/44'/195'/0'/0/0".to_string();
- let result = WrappedTron::from_json_bytes(&invalid_bytes, path);
- assert!(result.is_err());
- }
-
- #[test]
- fn test_from_json_bytes_invalid_json() {
- let invalid_json = b"not a json";
- let path = "m/44'/195'/0'/0/0".to_string();
- let result = WrappedTron::from_json_bytes(invalid_json, path);
- assert!(result.is_err());
- }
#[test]
fn test_signature_hash() {
diff --git a/rust/rust_c/src/tron/mod.rs b/rust/rust_c/src/tron/mod.rs
index 402da3d..a7ccae7 100644
--- a/rust/rust_c/src/tron/mod.rs
+++ b/rust/rust_c/src/tron/mod.rs
@@ -30,26 +30,31 @@ pub unsafe extern "C" fn tron_check_sign_request(
master_fingerprint: PtrBytes,
length: u32,
) -> PtrT<TransactionCheckResult> {
- if length != 4 {
+ if length != 4 {
return TransactionCheckResult::from(RustCError::InvalidMasterFingerprint).c_ptr();
}
-
let req = extract_ptr_with_type!(ptr, TronSignRequest);
- let json_bytes = req.get_sign_data();
- let path = req
- .get_derivation_path()
- .get_path()
- .unwrap_or_else(|| String::from(TRON_DEFAULT_PATH));
+ let mfp = extract_array!(master_fingerprint, u8, 4);
+ if let Ok(mfp) = (mfp.try_into() as Result<[u8; 4], _>) {
+ let derivation_path = req.get_derivation_path();
+ if let Some(ur_mfp) = derivation_path.get_source_fingerprint() {
+ if mfp != ur_mfp {
+ return TransactionCheckResult::from(RustCError::MasterFingerprintMismatch).c_ptr();
+ }
+ } else {
+ return TransactionCheckResult::from(RustCError::MasterFingerprintMismatch).c_ptr();
+ }
+ } else {
+ return TransactionCheckResult::from(RustCError::InvalidMasterFingerprint).c_ptr();
+ }
- let xpub = recover_c_char(x_pub);
-
- let xfp_bytes = extract_array!(master_fingerprint, u8, 4);
- let mut array = [0u8; 4];
- array.copy_from_slice(&xfp_bytes);
- let xfp = bitcoin::bip32::Fingerprint::from(array);
+ let x_pub_recovered = recover_c_char(x_pub);
+ let xpub_str = x_pub_recovered.as_str();
+ let sign_data = req.get_sign_data();
+ let path = req.get_derivation_path().get_path().unwrap_or_default();
- match app_tron::check_tx_request(&json_bytes, &path, xfp, &xpub) {
- Ok(_) => TransactionCheckResult::new().c_ptr(),
+ match app_tron::check_tx_request(&sign_data, &path, xpub_str) {
+ Ok(_) => TransactionCheckResult::new().c_ptr(),
Err(e) => TransactionCheckResult::from(e).c_ptr(),
}
}
diff --git a/src/ui/gui_chain/multi/web3/gui_trx.c b/src/ui/gui_chain/multi/web3/gui_trx.c
index ff6fc2d..ccd31d9 100644
--- a/src/ui/gui_chain/multi/web3/gui_trx.c
+++ b/src/ui/gui_chain/multi/web3/gui_trx.c
@@ -27,21 +27,6 @@ void GuiSetTrxUrData(URParseResult *urResult, URParseMultiResult *urMultiResult,
result = NULL; \
}
-// void *GuiGetTrxData(void)
-// {
-// CHECK_FREE_PARSE_RESULT(g_parseResult);
-// uint8_t mfp[4];
-// void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
-// QRCodeType urType = g_isMulti ? g_urMultiResult->ur_type : g_urResult->ur_type;
-// char *trxXpub = GetCurrentAccountPublicKey(XPUB_TYPE_TRX);
-// GetMasterFingerPrint(mfp);
-// do {
-// PtrT_TransactionParseResult_DisplayTron parseResult = tron_parse_keystone(data, urType, mfp, sizeof(mfp), trxXpub);
-// CHECK_CHAIN_BREAK(parseResult);
-// g_parseResult = (void *)parseResult;
-// } while (0);
-// return g_parseResult;
-// }
void *GuiGetTrxData(void)
{
CHECK_FREE_PARSE_RESULT(g_parseResult);
@@ -57,15 +42,6 @@ void *GuiGetTrxData(void)
return g_parseResult;
}
-// PtrT_TransactionCheckResult GuiGetTrxCheckResult(void)
-// {
-// uint8_t mfp[4];
-// void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
-// QRCodeType urType = g_isMulti ? g_urMultiResult->ur_type : g_urResult->ur_type;
-// char *trxXpub = GetCurrentAccountPublicKey(XPUB_TYPE_TRX);
-// GetMasterFingerPrint(mfp);
-// return tron_check_keystone(data, urType, mfp, sizeof(mfp), trxXpub);
-// }
PtrT_TransactionCheckResult GuiGetTrxCheckResult(void)
{
uint8_t mfp[4];
@@ -130,30 +106,6 @@ void GetTrxToken(void *indata, void *param, uint32_t maxLen)
strcpy_s((char *)indata, maxLen, trx->detail->token);
}
-// UREncodeResult *GuiGetTrxSignQrCodeData(void)
-// {
-// bool enable = IsPreviousLockScreenEnable();
-// SetLockScreen(false);
-// UREncodeResult *encodeResult = NULL;
-// void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
-// QRCodeType urType = g_isMulti ? g_urMultiResult->ur_type : g_urResult->ur_type;
-// uint8_t mfp[4];
-// GetMasterFingerPrint(mfp);
-// uint8_t seed[SEED_LEN];
-// do {
-// int ret = GetAccountSeed(GetCurrentAccountIndex(), seed, SecretCacheGetPassword());
-// if (ret != 0) {
-// break;
-// }
-// encodeResult = tron_sign_keystone(data, urType, mfp, sizeof(mfp), GetCurrentAccountPublicKey(XPUB_TYPE_TRX),
-// SOFTWARE_VERSION, seed, GetCurrentAccountSeedLen());
-// CHECK_CHAIN_BREAK(encodeResult);
-// } while (0);
-// memset_s(seed, sizeof(seed), 0, sizeof(seed));
-// ClearSecretCache();
-// SetLockScreen(enable);
-// return encodeResult;
-// }
UREncodeResult *GuiGetTrxSignQrCodeData(void)
{
bool enable = IsPreviousLockScreenEnable();
Why this scored 48/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.