refactor: zcash transparent and orchard logic
What changed, and why it matters
This commit is a large refactor of how the Keystone 3 firmware handles Zcash transactions. It splits the code into two build flavors: a 'multi-coins' build that supports only transparent (public) Zcash addresses using a normal xpub, and a 'cypherpunk' build that also supports shielded Orchard addresses using a unified full viewing key (UFVK). The change reorganizes feature flags, renames functions, and adjusts how Zcash account data is cached when wallets are created or unlocked. There is no explicit security fix or vulnerability disclosure in the commit message, and the diff itself is mostly structural. A few small items stand out as worth checking: a typo in a feature-guard macro (CYBERPUNK_VERSION vs CYPHERPUNK_VERSION) could leave the cypherpunk UI path disabled, and a debug printf was left in production key-handling code. On its own, this commit does not appear to introduce a clear exploitable vulnerability, but it is a partial refactor and the new multi-coins transparent-only path is simpler and exposes less shielded-key material than before.
Treat this as a code-quality and build-configuration review item rather than a confirmed vulnerability. Verify that the CYBERPUNK_VERSION typo in src/ui/gui_chain/multi/gui_zcash.c is intentional or fix it to CYPHERPUNK_VERSION. Remove the debug printf in account_public_info.c before release. Confirm that the new multi_coins transparent-only APIs correctly reject orchard/spend data and that feature flags are mutually exclusive where intended. Run tests for both zcash_multi_coins and zcash_cypherpunk builds to ensure no regression in transaction parsing or signing.
Security signals we found
Refactor splits Zcash shielded (Orchard/UFVK) and transparent-only code paths by build feature
Cypherpunk build continues to handle encrypted UFVK and Orchard actions; multi-coins build uses only transparent xpub
Likely typo in feature macro: CYBERPUNK_VERSION instead of CYPHERPUNK_VERSION in src/ui/gui_chain/multi/gui_zcash.c
Debug printf left in RSA_KEY handling path in src/crypto/account_public_info.c
Removal of ZCASH_UFVK_ENCRYPTED_0 from WEB3 chain table reduces shielded-key exposure in multi-coins builds
New SetupZcashSFP routine caches only seed fingerprint for WEB3 builds, while SetupZcashCache remains for cypherpunk builds
Evidence from the diff
The commit refactors Zcash PCZT (Partially Created Zcash Transaction) handling. It introduces separate Cargo features: app_zcash/zcash_vendor default-features are disabled at the workspace level; zcash_vendor now has transparent, orchard, multi_coins and cypherpunk features; rust_c exposes zcash, zcash_multi_coins and zcash_cypherpunk. Public APIs are split: check_pczt / parse_pczt become check_pczt_cypherpunk / parse_pczt_cypherpunk (require UFVK, include orchard checks) and check_pczt_multi_coins / parse_pczt_multi_coins (require only transparent xpub, no orchard). C FFI exports are renamed accordingly and gated by cfg. C code removes ZCASH_UFVK_ENCRYPTED_0 from the generic WEB3 chain table and moves UFVK handling behind CYPHERPUNK_VERSION; it adds SetupZcashSFP for WEB3 builds and keeps SetupZcashCache for CYPHERPUNK_VERSION. A debug printf ‘here, RSA_KEY’ is added in account_public_info.c. gui_zcash.c uses the new APIs but contains a likely typo: #ifdef CYBERPUNK_VERSION instead of CYPHERPUNK_VERSION, which would disable the cypherpunk branch. gui_btc.c changes one error-return macro from CHECK_ERRCODE_RETURN to CHECK_ERRCODE_RETURN_NULL. No explicit security bug or CVE is mentioned.
Changed components
rust/apps/zcashrust/apps/zcash/src/pczt/check.rsrust/apps/zcash/src/pczt/parse.rsrust/apps/zcash/src/pczt/sign.rsrust/rust_c/src/zcash/mod.rsrust/zcash_vendorsrc/crypto/account_public_info.csrc/managers/account_manager.csrc/managers/keystore.csrc/ui/gui_chain/multi/gui_zcash.csrc/ui/gui_chain/gui_btc.cInspect captured patch +289 / −120
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index a89bf43..8f40c5c 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -48,14 +48,14 @@ app_tron = { path = "apps/tron" }
app_utils = { path = "apps/utils" }
app_wallets = { path = "apps/wallets" }
app_xrp = { path = "apps/xrp" }
-app_zcash = { path = "apps/zcash" }
+app_zcash = { path = "apps/zcash", default-features = false}
app_monero = { path = "apps/monero" }
app_iota = { path = "apps/iota" }
keystore = { path = "keystore", default-features = false }
tools = { path = "tools" }
sim_qr_reader = { path = "sim_qr_reader" }
rust_tools = { path = "tools" }
-zcash_vendor = { path = "zcash_vendor" }
+zcash_vendor = { path = "zcash_vendor", default-features = false}
# third party dependencies
cty = "0.2.0"
diff --git a/rust/apps/wallets/src/metamask.rs b/rust/apps/wallets/src/metamask.rs
index 62a8e53..1ff5c47 100644
--- a/rust/apps/wallets/src/metamask.rs
+++ b/rust/apps/wallets/src/metamask.rs
@@ -155,7 +155,9 @@ fn get_path_component(index: Option<u32>, hardened: bool) -> URResult<PathCompon
mod tests {
extern crate std;
- use crate::metamask::{generate_ledger_live_account, generate_standard_legacy_hd_key, ETHAccountTypeApp};
+ use crate::metamask::{
+ generate_ledger_live_account, generate_standard_legacy_hd_key, ETHAccountTypeApp,
+ };
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
@@ -206,12 +208,16 @@ mod tests {
let x_pub = "xpub6C8zKiZZ8V75XynjThhvdjy7hbnJHAFkhW7jL9EvBCsRFSRov4sXUJATU6CqUF9BxAbryiU3eghdHDLbwgF8ASE4AwHTzkLHaHsbwiCnkHc";
// Test Bip44Standard
- let result = generate_standard_legacy_hd_key(&mfp, x_pub, ETHAccountTypeApp::Bip44Standard, None).unwrap();
+ let result =
+ generate_standard_legacy_hd_key(&mfp, x_pub, ETHAccountTypeApp::Bip44Standard, None)
+ .unwrap();
let cbor: Vec<u8> = result.try_into().unwrap();
assert!(!cbor.is_empty());
// Test LedgerLegacy
- let result = generate_standard_legacy_hd_key(&mfp, x_pub, ETHAccountTypeApp::LedgerLegacy, None).unwrap();
+ let result =
+ generate_standard_legacy_hd_key(&mfp, x_pub, ETHAccountTypeApp::LedgerLegacy, None)
+ .unwrap();
let cbor: Vec<u8> = result.try_into().unwrap();
assert!(!cbor.is_empty());
}
diff --git a/rust/apps/wallets/src/okx.rs b/rust/apps/wallets/src/okx.rs
index 4086db6..5e53e14 100644
--- a/rust/apps/wallets/src/okx.rs
+++ b/rust/apps/wallets/src/okx.rs
@@ -206,7 +206,7 @@ mod tests {
let eth_xpub_str = "xpub6C8zKiZZ8V75XynjThhvdjy7hbnJHAFkhW7jL9EvBCsRFSRov4sXUJATU6CqUF9BxAbryiU3eghdHDLbwgF8ASE4AwHTzkLHaHsbwiCnkHc";
let eth_xpub = Xpub::from_str(eth_xpub_str).unwrap();
let eth_xpub_bytes = serialize_xpub(ð_xpub);
-
+
let eth_path = DerivationPath::from_str("m/44'/60'/0'").unwrap();
let eth_key = ExtendedPublicKey {
path: eth_path,
@@ -228,15 +228,18 @@ mod tests {
let result = generate_crypto_multi_accounts(mfp, serial, keys, device_type, device_version);
assert!(result.is_ok());
-
+
let multi_accounts = result.unwrap();
let cbor: Vec<u8> = multi_accounts.clone().try_into().unwrap();
assert!(!cbor.is_empty());
-
+
// Verify device info
assert_eq!(multi_accounts.get_device(), Some(device_type.to_string()));
- assert_eq!(multi_accounts.get_device_version(), Some(device_version.to_string()));
-
+ assert_eq!(
+ multi_accounts.get_device_version(),
+ Some(device_version.to_string())
+ );
+
// Verify keys count
// ETH generates 2 keys (standard + ledger live), BTC generates 1 key. Total 3.
assert_eq!(multi_accounts.get_keys().len(), 3);
diff --git a/rust/apps/wallets/src/thor_wallet.rs b/rust/apps/wallets/src/thor_wallet.rs
index 33b0ea1..258073d 100644
--- a/rust/apps/wallets/src/thor_wallet.rs
+++ b/rust/apps/wallets/src/thor_wallet.rs
@@ -198,7 +198,7 @@ mod tests {
let eth_xpub_str = "xpub6C8zKiZZ8V75XynjThhvdjy7hbnJHAFkhW7jL9EvBCsRFSRov4sXUJATU6CqUF9BxAbryiU3eghdHDLbwgF8ASE4AwHTzkLHaHsbwiCnkHc";
let eth_xpub = Xpub::from_str(eth_xpub_str).unwrap();
let eth_xpub_bytes = serialize_xpub(ð_xpub);
-
+
let eth_path = DerivationPath::from_str("m/44'/60'/0'").unwrap();
let eth_key = ExtendedPublicKey {
path: eth_path,
@@ -231,15 +231,18 @@ mod tests {
let result = generate_crypto_multi_accounts(mfp, serial, keys, device_type, device_version);
assert!(result.is_ok());
-
+
let multi_accounts = result.unwrap();
let cbor: Vec<u8> = multi_accounts.clone().try_into().unwrap();
assert!(!cbor.is_empty());
-
+
// Verify device info
assert_eq!(multi_accounts.get_device(), Some(device_type.to_string()));
- assert_eq!(multi_accounts.get_device_version(), Some(device_version.to_string()));
-
+ assert_eq!(
+ multi_accounts.get_device_version(),
+ Some(device_version.to_string())
+ );
+
// Verify keys count
// ETH generates 2 keys (standard + ledger live), BTC generates 1 key, Thorchain generates 1 key. Total 4.
assert_eq!(multi_accounts.get_keys().len(), 4);
diff --git a/rust/apps/wallets/src/zcash.rs b/rust/apps/wallets/src/zcash.rs
index 8a774da..4bdcdad 100644
--- a/rust/apps/wallets/src/zcash.rs
+++ b/rust/apps/wallets/src/zcash.rs
@@ -37,8 +37,8 @@ pub fn generate_sync_ur(
#[cfg(test)]
mod tests {
use super::*;
- use alloc::vec;
use alloc::string::ToString;
+ use alloc::vec;
#[test]
fn test_generate_sync_ur() {
@@ -64,4 +64,3 @@ mod tests {
assert!(!cbor.is_empty());
}
}
-
diff --git a/rust/apps/zcash/src/lib.rs b/rust/apps/zcash/src/lib.rs
index 59b0d23..9e4762e 100644
--- a/rust/apps/zcash/src/lib.rs
+++ b/rust/apps/zcash/src/lib.rs
@@ -56,20 +56,66 @@ pub fn get_address<P: consensus::Parameters>(params: &P, ufvk_text: &str) -> Res
/// * `ZcashError::InvalidDataError` - If the UFVK cannot be decoded or the account index is invalid
/// * `ZcashError::InvalidPczt` - If the PCZT data is malformed or cannot be parsed
/// * Other errors from the underlying validation process
-pub fn check_pczt<P: consensus::Parameters>(
+#[cfg(feature = "cypherpunk")]
+pub fn check_pczt_cypherpunk<P: consensus::Parameters>(
params: &P,
pczt: &[u8],
ufvk_text: &str,
seed_fingerprint: &[u8; 32],
account_index: u32,
) -> Result<()> {
+ let pczt =
+ Pczt::parse(pczt).map_err(|_e| ZcashError::InvalidPczt("invalid pczt data".to_string()))?;
+ let account_index = zip32::AccountId::try_from(account_index)
+ .map_err(|_e| ZcashError::InvalidDataError("invalid account index".to_string()))?;
let ufvk = UnifiedFullViewingKey::decode(params, ufvk_text)
.map_err(|e| ZcashError::InvalidDataError(e.to_string()))?;
+ let xpub = ufvk.transparent().ok_or(ZcashError::InvalidDataError(
+ "transparent xpub is not present".to_string(),
+ ))?;
+ pczt::check::check_pczt_orchard(params, seed_fingerprint, account_index, &ufvk, &pczt)?;
+ pczt::check::check_pczt_transparent(params, seed_fingerprint, account_index, xpub, &pczt)
+}
+
+#[cfg(feature = "multi_coins")]
+pub fn check_pczt_multi_coins<P: consensus::Parameters>(
+ params: &P,
+ pczt: &[u8],
+ xpub: &str,
+ seed_fingerprint: &[u8; 32],
+ account_index: u32,
+) -> Result<()> {
+ use core::str::FromStr;
+ use zcash_vendor::{bip32, transparent};
+
+ let xpub: bip32::ExtendedPublicKey<bitcoin::secp256k1::PublicKey> =
+ bip32::ExtendedPublicKey::from_str(xpub)
+ .map_err(|e| ZcashError::InvalidDataError(e.to_string()))?;
+
+ let key = {
+ let chain_code = xpub.attrs().chain_code;
+ let pubkey = xpub.public_key().serialize();
+ let mut bytes = [0u8; 65];
+ bytes[..32].copy_from_slice(&chain_code);
+ bytes[32..].copy_from_slice(&pubkey);
+ bytes
+ };
+
+ let account_pubkey = transparent::keys::AccountPubKey::deserialize(&key)
+ .map_err(|e| ZcashError::InvalidDataError(e.to_string()))?;
+
let pczt =
Pczt::parse(pczt).map_err(|_e| ZcashError::InvalidPczt("invalid pczt data".to_string()))?;
let account_index = zip32::AccountId::try_from(account_index)
.map_err(|_e| ZcashError::InvalidDataError("invalid account index".to_string()))?;
- pczt::check::check_pczt(params, seed_fingerprint, account_index, &ufvk, &pczt)
+
+ pczt::check::check_pczt_transparent(
+ params,
+ seed_fingerprint,
+ account_index,
+ &account_pubkey,
+ &pczt,
+ )
}
/// Parses a Partially Created Zcash Transaction (PCZT) and extracts its details.
@@ -90,7 +136,8 @@ pub fn check_pczt<P: consensus::Parameters>(
/// * `ZcashError::InvalidDataError` - If the UFVK cannot be decoded
/// * `ZcashError::InvalidPczt` - If the PCZT data is malformed or cannot be parsed
/// * Other errors from the underlying parsing process
-pub fn parse_pczt<P: consensus::Parameters>(
+#[cfg(feature = "cypherpunk")]
+pub fn parse_pczt_cypherpunk<P: consensus::Parameters>(
params: &P,
pczt: &[u8],
ufvk_text: &str,
@@ -100,7 +147,19 @@ pub fn parse_pczt<P: consensus::Parameters>(
.map_err(|e| ZcashError::InvalidDataError(e.to_string()))?;
let pczt =
Pczt::parse(pczt).map_err(|_e| ZcashError::InvalidPczt("invalid pczt data".to_string()))?;
- pczt::parse::parse_pczt(params, seed_fingerprint, &ufvk, &pczt)
+ pczt::parse::parse_pczt_cypherpunk(params, seed_fingerprint, &ufvk, &pczt)
+}
+
+#[cfg(feature = "multi_coins")]
+pub fn parse_pczt_multi_coins<P: consensus::Parameters>(
+ params: &P,
+ pczt: &[u8],
+ seed_fingerprint: &[u8; 32],
+) -> Result<ParsedPczt> {
+ let pczt =
+ Pczt::parse(pczt).map_err(|_e| ZcashError::InvalidPczt("invalid pczt data".to_string()))?;
+
+ pczt::parse::parse_pczt_multi_coins(params, seed_fingerprint, &pczt)
}
/// Signs a Partially Created Zcash Transaction (PCZT) using a seed.
@@ -124,6 +183,7 @@ pub fn sign_pczt(pczt: &[u8], seed: &[u8]) -> Result<Vec<u8>> {
pczt::sign::sign_pczt(pczt, seed)
}
+#[cfg(feature = "cypherpunk")]
#[cfg(test)]
mod tests {
use consensus::MainNetwork;
diff --git a/rust/apps/zcash/src/pczt/check.rs b/rust/apps/zcash/src/pczt/check.rs
index 591b82b..22b7a3c 100644
--- a/rust/apps/zcash/src/pczt/check.rs
+++ b/rust/apps/zcash/src/pczt/check.rs
@@ -16,17 +16,14 @@ use zcash_vendor::{
};
#[cfg(feature = "cypherpunk")]
-pub fn check_pczt<P: consensus::Parameters>(
+pub fn check_pczt_orchard<P: consensus::Parameters>(
params: &P,
seed_fingerprint: &[u8; 32],
account_index: zip32::AccountId,
ufvk: &UnifiedFullViewingKey,
pczt: &Pczt,
) -> Result<(), ZcashError> {
- // checking xpub and orchard keys.
- let xpub = ufvk.transparent().ok_or(ZcashError::InvalidDataError(
- "transparent xpub is not present".to_string(),
- ))?;
+ // checking orchard keys.
let orchard = ufvk.orchard().ok_or(ZcashError::InvalidDataError(
"orchard fvk is not present".to_string(),
))?;
@@ -35,27 +32,17 @@ pub fn check_pczt<P: consensus::Parameters>(
check_orchard(params, seed_fingerprint, account_index, orchard, bundle)
.map_err(pczt::roles::verifier::OrchardError::Custom)
})
- .map_err(|e| ZcashError::InvalidDataError(alloc::format!("{e:?}")))?
- .with_transparent(|bundle| {
- check_transparent(params, seed_fingerprint, account_index, xpub, bundle)
- .map_err(pczt::roles::verifier::TransparentError::Custom)
- })
.map_err(|e| ZcashError::InvalidDataError(alloc::format!("{e:?}")))?;
Ok(())
}
-#[cfg(not(feature = "cypherpunk"))]
-pub fn check_pczt<P: consensus::Parameters>(
+pub fn check_pczt_transparent<P: consensus::Parameters>(
params: &P,
seed_fingerprint: &[u8; 32],
account_index: zip32::AccountId,
- ufvk: &UnifiedFullViewingKey,
+ xpub: &AccountPubKey,
pczt: &Pczt,
) -> Result<(), ZcashError> {
- // checking xpub and orchard keys.
- let xpub = ufvk.transparent().ok_or(ZcashError::InvalidDataError(
- "transparent xpub is not present".to_string(),
- ))?;
Verifier::new(pczt.clone())
.with_transparent(|bundle| {
check_transparent(params, seed_fingerprint, account_index, xpub, bundle)
@@ -266,8 +253,7 @@ fn check_transparent_output<P: consensus::Parameters>(
}
}
-
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
// check orchard bundle
fn check_orchard<P: consensus::Parameters>(
params: &P,
@@ -299,7 +285,7 @@ fn check_orchard<P: consensus::Parameters>(
}
}
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
// check orchard action
fn check_action<P: consensus::Parameters>(
params: &P,
@@ -318,7 +304,7 @@ fn check_action<P: consensus::Parameters>(
check_action_output(action)
}
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
// check spend nullifier
fn check_action_spend<P: consensus::Parameters>(
params: &P,
@@ -360,7 +346,7 @@ fn check_action_spend<P: consensus::Parameters>(
Ok(())
}
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
//check output cmx
fn check_action_output(action: &orchard::pczt::Action) -> Result<(), ZcashError> {
action
@@ -377,6 +363,7 @@ fn check_action_output(action: &orchard::pczt::Action) -> Result<(), ZcashError>
Ok(())
}
+#[cfg(feature = "cypherpunk")]
#[cfg(test)]
mod tests {
use super::*;
@@ -399,7 +386,7 @@ mod tests {
let fingerprint = fingerprint.try_into().unwrap();
- let result = check_pczt(
+ let result = check_pczt_orchard(
&MAIN_NETWORK,
&fingerprint,
zip32::AccountId::ZERO,
diff --git a/rust/apps/zcash/src/pczt/parse.rs b/rust/apps/zcash/src/pczt/parse.rs
index 6a127e0..7f9bad8 100644
--- a/rust/apps/zcash/src/pczt/parse.rs
+++ b/rust/apps/zcash/src/pczt/parse.rs
@@ -3,9 +3,7 @@ use alloc::{
string::{String, ToString},
vec,
};
-use zcash_note_encryption::{
- try_output_recovery_with_ovk, try_output_recovery_with_pkd_esk,
-};
+use zcash_note_encryption::{try_output_recovery_with_ovk, try_output_recovery_with_pkd_esk};
use zcash_vendor::{
pczt::{self, roles::verifier::Verifier, Pczt},
ripemd::{Digest, Ripemd160},
@@ -22,6 +20,8 @@ use zcash_vendor::{
},
};
+#[cfg(feature = "cypherpunk")]
+use zcash_note_encryption::Domain;
#[cfg(feature = "cypherpunk")]
use zcash_vendor::orchard::{
self, keys::OutgoingViewingKey, note::Note, note_encryption::OrchardDomain, Address,
@@ -50,7 +50,7 @@ fn format_zec_value(value: f64) -> String {
/// - `Ok(None)` if the output cannot be decrypted.
/// - `Err(_)` if `ovk` is `None` and the PCZT is missing fields needed to directly
/// decrypt the output.
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
pub fn decode_output_enc_ciphertext(
action: &orchard::pczt::Action,
ovk: Option<&OutgoingViewingKey>,
@@ -117,8 +117,8 @@ pub fn decode_output_enc_ciphertext(
/// 3. Handles Sapling pool interactions (though full Sapling decoding is not supported)
/// 4. Computes transfer values and fees
/// 5. Returns a structured representation of the transaction
-#[cfg(feature = "orchard")]
-pub fn parse_pczt<P: consensus::Parameters>(
+#[cfg(feature = "cypherpunk")]
+pub fn parse_pczt_cypherpunk<P: consensus::Parameters>(
params: &P,
seed_fingerprint: &[u8; 32],
ufvk: &UnifiedFullViewingKey,
@@ -212,11 +212,10 @@ pub fn parse_pczt<P: consensus::Parameters>(
has_sapling,
))
}
-#[cfg(not(feature = "orchard"))]
-pub fn parse_pczt<P: consensus::Parameters>(
+#[cfg(feature = "multi_coins")]
+pub fn parse_pczt_multi_coins<P: consensus::Parameters>(
params: &P,
seed_fingerprint: &[u8; 32],
- ufvk: &UnifiedFullViewingKey,
pczt: &Pczt,
) -> Result<ParsedPczt, ZcashError> {
let mut parsed_transparent = None;
@@ -411,7 +410,7 @@ fn parse_transparent_output(
}
}
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
fn parse_orchard<P: consensus::Parameters>(
params: &P,
seed_fingerprint: &[u8; 32],
@@ -444,7 +443,7 @@ fn parse_orchard<P: consensus::Parameters>(
}
}
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
fn parse_orchard_spend(
seed_fingerprint: &[u8; 32],
spend: &orchard::pczt::Spend,
@@ -465,7 +464,7 @@ fn parse_orchard_spend(
Ok(ParsedFrom::new(None, zec_value, value, is_mine))
}
-#[cfg(feature="cypherpunk")]
+#[cfg(feature = "cypherpunk")]
fn parse_orchard_output<P: consensus::Parameters>(
params: &P,
ufvk: &UnifiedFullViewingKey,
@@ -648,6 +647,7 @@ fn decode_memo(memo_bytes: [u8; 512]) -> Option<String> {
Some(hex::encode(memo_bytes))
}
+#[cfg(feature = "cypherpunk")]
#[cfg(test)]
mod tests {
use super::*;
@@ -690,7 +690,7 @@ mod tests {
let fingerprint = fingerprint.try_into().unwrap();
let unified_fvk = UnifiedFullViewingKey::decode(&MAIN_NETWORK, ufvk).unwrap();
- let result = parse_pczt(&MAIN_NETWORK, &fingerprint, &unified_fvk, &pczt);
+ let result = parse_pczt_cypherpunk(&MAIN_NETWORK, &fingerprint, &unified_fvk, &pczt);
assert!(result.is_ok());
let result = result.unwrap();
assert!(!result.get_has_sapling());
diff --git a/rust/apps/zcash/src/pczt/sign.rs b/rust/apps/zcash/src/pczt/sign.rs
index 3ea000a..ee85b91 100644
--- a/rust/apps/zcash/src/pczt/sign.rs
+++ b/rust/apps/zcash/src/pczt/sign.rs
@@ -75,7 +75,7 @@ impl PcztSigner for SeedSigner<'_> {
Ok(())
}
- #[cfg(feature = "orchard")]
+ #[cfg(feature = "cypherpunk")]
fn sign_orchard(
&self,
action: &mut orchard::pczt::Action,
diff --git a/rust/rust_c/Cargo.toml b/rust/rust_c/Cargo.toml
index 1fd28ae..9bd0730 100644
--- a/rust/rust_c/Cargo.toml
+++ b/rust/rust_c/Cargo.toml
@@ -28,7 +28,7 @@ cipher = { workspace = true }
minicbor = { workspace = true }
#keystone owned
sim_qr_reader = { workspace = true, optional = true }
-keystore = { workspace = true, default-features = false}
+keystore = { workspace = true, default-features = false }
ur-registry = { workspace = true }
ur-parse-lib = { workspace = true }
zcash_vendor = { workspace = true, optional = true }
@@ -82,8 +82,18 @@ sui = ["dep:app_sui"]
ton = ["dep:app_ton"]
tron = ["dep:app_tron"]
xrp = ["dep:app_xrp"]
-zcash = ["dep:app_zcash", "dep:zcash_vendor", "app_zcash/multi_coins", "zcash_vendor/multi_coins"]
-zcash_cypherpunk = ["dep:app_zcash", "dep:zcash_vendor", "app_zcash/cypherpunk", "zcash_vendor/cypherpunk"]
+zcash = [
+ "dep:app_zcash",
+ "dep:zcash_vendor",
+]
+zcash_multi_coins = [
+ "zcash",
+ "app_zcash/multi_coins",
+]
+zcash_cypherpunk = [
+ "zcash",
+ "app_zcash/cypherpunk",
+]
monero = ["dep:app_monero"]
avalanche = ["dep:app_avalanche"]
iota = ["dep:app_iota"]
@@ -111,11 +121,11 @@ multi-coins = [
"xrp",
"avalanche",
"iota",
- "zcash",
+ "zcash_multi_coins",
"keystore/multi_coins",
]
-btc-only = ["bitcoin"]
+btc-only = ["bitcoin", "keystore/multi_coins"]
cypherpunk = ["bitcoin", "zcash_cypherpunk", "monero", "keystore/cypherpunk"]
@@ -133,7 +143,7 @@ simulator-multi-coins = ["simulator", "multi-coins"]
simulator-btc-only = ["simulator", "btc-only"]
simulator-cypherpunk = ["simulator", "cypherpunk"]
# make IDE happy
-default = ["simulator-multi-coins"]
+default = ["simulator-cypherpunk"]
[dev-dependencies]
keystore = { path = "../keystore" }
diff --git a/rust/rust_c/src/zcash/mod.rs b/rust/rust_c/src/zcash/mod.rs
index f488b0f..530e46a 100644
--- a/rust/rust_c/src/zcash/mod.rs
+++ b/rust/rust_c/src/zcash/mod.rs
@@ -70,7 +70,8 @@ pub unsafe extern "C" fn generate_zcash_default_address(
}
#[no_mangle]
-pub unsafe extern "C" fn check_zcash_tx(
+#[cfg(feature = "cypherpunk")]
+pub unsafe extern "C" fn check_zcash_tx_cypherpunk(
tx: PtrUR,
ufvk: PtrString,
seed_fingerprint: PtrBytes,
@@ -87,7 +88,7 @@ pub unsafe extern "C" fn check_zcash_tx(
let ufvk_text = unsafe { recover_c_char(ufvk) };
let seed_fingerprint = extract_array!(seed_fingerprint, u8, 32);
let seed_fingerprint = seed_fingerprint.try_into().unwrap();
- match app_zcash::check_pczt(
+ match app_zcash::check_pczt_cypherpunk(
&MainNetwork,
&pczt.get_data(),
&ufvk_text,
@@ -99,8 +100,40 @@ pub unsafe extern "C" fn check_zcash_tx(
}
}
+#[cfg(feature = "multi-coins")]
#[no_mangle]
-pub unsafe extern "C" fn parse_zcash_tx(
+pub unsafe extern "C" fn check_zcash_tx_multi_coins(
+ tx: PtrUR,
+ xpub: PtrString,
+ seed_fingerprint: PtrBytes,
+ account_index: u32,
+ disabled: bool,
+) -> *mut TransactionCheckResult {
+ if disabled {
+ return TransactionCheckResult::from(RustCError::UnsupportedTransaction(
+ "zcash is not supported for slip39 and passphrase wallet now".to_string(),
+ ))
+ .c_ptr();
+ }
+ let pczt = extract_ptr_with_type!(tx, ZcashPczt);
+ let xpub_text = unsafe { recover_c_char(xpub) };
+ let seed_fingerprint = extract_array!(seed_fingerprint, u8, 32);
+ let seed_fingerprint = seed_fingerprint.try_into().unwrap();
+ match app_zcash::check_pczt_multi_coins(
+ &MainNetwork,
+ &pczt.get_data(),
+ &xpub_text,
+ seed_fingerprint,
+ account_index,
+ ) {
+ Ok(_) => TransactionCheckResult::new().c_ptr(),
+ Err(e) => TransactionCheckResult::from(e).c_ptr(),
+ }
+}
+
+#[cfg(feature = "cypherpunk")]
+#[no_mangle]
+pub unsafe extern "C" fn parse_zcash_tx_cypherpunk(
tx: PtrUR,
ufvk: PtrString,
seed_fingerprint: PtrBytes,
@@ -109,7 +142,27 @@ pub unsafe extern "C" fn parse_zcash_tx(
let ufvk_text = unsafe { recover_c_char(ufvk) };
let seed_fingerprint = extract_array!(seed_fingerprint, u8, 32);
let seed_fingerprint = seed_fingerprint.try_into().unwrap();
- match app_zcash::parse_pczt(&MainNetwork, &pczt.get_data(), &ufvk_text, seed_fingerprint) {
+ match app_zcash::parse_pczt_cypherpunk(
+ &MainNetwork,
+ &pczt.get_data(),
+ &ufvk_text,
+ seed_fingerprint,
+ ) {
+ Ok(pczt) => TransactionParseResult::success(DisplayPczt::from(&pczt).c_ptr()).c_ptr(),
+ Err(e) => TransactionParseResult::from(e).c_ptr(),
+ }
+}
+
+#[cfg(feature = "multi-coins")]
+#[no_mangle]
+pub unsafe extern "C" fn parse_zcash_tx_multi_coins(
+ tx: PtrUR,
+ seed_fingerprint: PtrBytes,
+) -> Ptr<TransactionParseResult<DisplayPczt>> {
+ let pczt = extract_ptr_with_type!(tx, ZcashPczt);
+ let seed_fingerprint = extract_array!(seed_fingerprint, u8, 32);
+ let seed_fingerprint = seed_fingerprint.try_into().unwrap();
+ match app_zcash::parse_pczt_multi_coins(&MainNetwork, &pczt.get_data(), seed_fingerprint) {
Ok(pczt) => TransactionParseResult::success(DisplayPczt::from(&pczt).c_ptr()).c_ptr(),
Err(e) => TransactionParseResult::from(e).c_ptr(),
}
diff --git a/rust/zcash_vendor/Cargo.toml b/rust/zcash_vendor/Cargo.toml
index dfb3f70..499ea1f 100644
--- a/rust/zcash_vendor/Cargo.toml
+++ b/rust/zcash_vendor/Cargo.toml
@@ -73,11 +73,11 @@ incrementalmerkletree-testing = { version = "0.3" }
[features]
-default = ["multi_coins"]
-multi_coins = ["pczt/transparent", "zcash_keys/transparent-inputs"]
-cypherpunk = [
- "pczt/transparent",
- "zcash_keys/transparent-inputs",
+default = ["cypherpunk"]
+multi_coins = ["transparent"]
+cypherpunk = ["transparent", "orchard"]
+transparent = ["pczt/transparent", "zcash_keys/transparent-inputs"]
+orchard = [
"pczt/orchard",
"zcash_keys/orchard",
"dep:orchard",
diff --git a/rust/zcash_vendor/src/pczt_ext.rs b/rust/zcash_vendor/src/pczt_ext.rs
index f8ddf33..73e84ef 100644
--- a/rust/zcash_vendor/src/pczt_ext.rs
+++ b/rust/zcash_vendor/src/pczt_ext.rs
@@ -92,7 +92,7 @@ pub type TransparentSignatureDER = Vec<u8>;
pub trait PcztSigner {
type Error;
- #[cfg(feature = "multi_coins")]
+ #[cfg(feature = "transparent")]
fn sign_transparent<F>(
&self,
index: usize,
@@ -102,7 +102,7 @@ pub trait PcztSigner {
where
F: FnOnce(SignableInput) -> [u8; 32];
- #[cfg(feature = "cypherpunk")]
+ #[cfg(feature = "orchard")]
fn sign_orchard(
&self,
action: &mut orchard::pczt::Action,
@@ -390,7 +390,7 @@ fn transparent_sig_digest(pczt: &Pczt, input_info: Option<SignableInput>) -> Has
}
}
-#[cfg(feature = "multi_coins")]
+#[cfg(feature = "transparent")]
pub fn sign_transparent<T>(llsigner: Signer, signer: &T) -> Result<Signer, T::Error>
where
T: PcztSigner,
@@ -429,33 +429,32 @@ where
})
}
-#[cfg(feature = "cypherpunk")]
+#[cfg(feature = "orchard")]
pub fn sign_orchard<T>(llsigner: Signer, signer: &T) -> Result<Signer, T::Error>
where
T: PcztSigner,
T::Error: From<orchard::pczt::ParseError>,
+ T::Error: From<transparent::pczt::ParseError>,
{
- llsigner
- .sign_orchard_with::<T::Error, _>(|pczt, signable, tx_modifiable| {
- let lock_time = determine_lock_time(pczt.global(), pczt.transparent().inputs())
- .ok_or(transparent::pczt::ParseError::InvalidRequiredHeightLocktime)?;
- signable.actions_mut().iter_mut().try_for_each(|action| {
- match action.spend().value().map(|v| v.inner()) {
- //dummy spend maybe
- Some(0) | None => {
- return Ok(());
- }
- Some(_) => {
- signer
- .sign_orchard(action, shielded_sig_commitment(pczt, lock_time, None))?;
- *tx_modifiable &= !(FLAG_TRANSPARENT_INPUTS_MODIFIABLE
- | FLAG_TRANSPARENT_OUTPUTS_MODIFIABLE
- | FLAG_SHIELDED_MODIFIABLE);
- }
+ llsigner.sign_orchard_with::<T::Error, _>(|pczt, signable, tx_modifiable| {
+ let lock_time = determine_lock_time(pczt.global(), pczt.transparent().inputs())
+ .ok_or(transparent::pczt::ParseError::InvalidRequiredHeightLocktime)?;
+ signable.actions_mut().iter_mut().try_for_each(|action| {
+ match action.spend().value().map(|v| v.inner()) {
+ //dummy spend maybe
+ Some(0) | None => {
+ return Ok(());
}
- Ok(())
- })
+ Some(_) => {
+ signer.sign_orchard(action, shielded_sig_commitment(pczt, lock_time, None))?;
+ *tx_modifiable &= !(FLAG_TRANSPARENT_INPUTS_MODIFIABLE
+ | FLAG_TRANSPARENT_OUTPUTS_MODIFIABLE
+ | FLAG_SHIELDED_MODIFIABLE);
+ }
+ }
+ Ok(())
})
+ })
}
#[cfg(feature = "cypherpunk")]
@@ -501,7 +500,7 @@ mod tests {
"0ee1912a92e13f43e2511d9c0a12ab26c165391eefc7311e382d752806e6cb8a"
);
assert_eq!(
- hex::encode(sheilded_sig_commitment(&pczt, 0, None).as_bytes()),
+ hex::encode(shielded_sig_commitment(&pczt, 0, None).as_bytes()),
"bd0488e0117fe59e2b58fe9897ce803200ad72f74a9a94594217a6a79050f66f"
);
}
@@ -539,7 +538,7 @@ mod tests {
"56dd210c9d1813eda55d7e2abea55091759b53deec092a4eda9e6f1b536b527a"
);
assert_eq!(
- hex::encode(sheilded_sig_commitment(&pczt, 0, None).as_bytes()),
+ hex::encode(shielded_sig_commitment(&pczt, 0, None).as_bytes()),
"fea284c0b63a4de21c2f660587b2e04461f7089d6c9f8c2e60a3caed77c037ae"
);
@@ -553,7 +552,7 @@ mod tests {
Zatoshis::from_u64(*pczt.transparent().inputs()[0].value()).unwrap(),
);
assert_eq!(
- hex::encode(sheilded_sig_commitment(&pczt, 0, Some(signable_input)).as_bytes()),
+ hex::encode(shielded_sig_commitment(&pczt, 0, Some(signable_input)).as_bytes()),
"a2865e1c7f3de700eee25fe233da6bbdab267d524bc788998485359441ad3140"
);
let script_code = Script(pczt.transparent().inputs()[1].script_pubkey().clone());
@@ -565,7 +564,7 @@ mod tests {
Zatoshis::from_u64(*pczt.transparent().inputs()[1].value()).unwrap(),
);
assert_eq!(
- hex::encode(sheilded_sig_commitment(&pczt, 0, Some(signable_input2)).as_bytes()),
+ hex::encode(shielded_sig_commitment(&pczt, 0, Some(signable_input2)).as_bytes()),
"9c10678495dfdb1f29beb6583d652bc66cb4e3d27d24d75fb6922f230e9953e8"
);
}
@@ -603,7 +602,7 @@ mod tests {
"90dc4739bdcae8f81c162213e9742d988b6abd29beecf1203e1a59a794e8cb4b"
);
assert_eq!(
- hex::encode(sheilded_sig_commitment(&pczt, 0, None).as_bytes()),
+ hex::encode(shielded_sig_commitment(&pczt, 0, None).as_bytes()),
"d9b80aac7a7e0f9cd525572877656bd923ff0c557be9a1ff16ff6e8e389ccc81"
);
}
diff --git a/src/crypto/account_public_info.c b/src/crypto/account_public_info.c
index 133074e..8aabcaf 100644
--- a/src/crypto/account_public_info.c
+++ b/src/crypto/account_public_info.c
@@ -524,7 +524,6 @@ static const ChainItem_t g_chainTable[] = {
{XPUB_TYPE_TON_NATIVE, TON_NATIVE, "ton", "" },
{PUBLIC_INFO_TON_CHECKSUM, TON_CHECKSUM, "ton_checksum", "" },
{XPUB_TYPE_ZEC_TRANSPARENT_LEGACY,SECP256K1, "zec_transparent_legacy", "M/44'/133'/0'" },
- {ZCASH_UFVK_ENCRYPTED_0, ZCASH_UFVK_ENCRYPTED, "zcash_ufvk_0", "M/32'/133'/0'" },
#endif
#ifdef CYPHERPUNK_VERSION
@@ -605,6 +604,7 @@ static SimpleResponse_c_char *ProcessKeyType(uint8_t *seed, int len, int cryptoK
#ifdef WEB3_VERSION
case RSA_KEY: {
+ printf("here, RSA_KEY\n");
Rsa_primes_t *primes = FlashReadRsaPrimes();
if (primes == NULL)
return NULL;
diff --git a/src/crypto/account_public_info.h b/src/crypto/account_public_info.h
index 6ab650e..dc3b2b8 100644
--- a/src/crypto/account_public_info.h
+++ b/src/crypto/account_public_info.h
@@ -237,7 +237,6 @@ typedef enum {
XPUB_TYPE_TON_NATIVE,
PUBLIC_INFO_TON_CHECKSUM,
XPUB_TYPE_ZEC_TRANSPARENT_LEGACY,
- ZCASH_UFVK_ENCRYPTED_0,
#endif
#ifdef CYPHERPUNK_VERSION
diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c
index 06afc82..9a29c9e 100644
--- a/src/crypto/rsa.c
+++ b/src/crypto/rsa.c
@@ -65,7 +65,6 @@ Rsa_primes_t *FlashReadRsaPrimes(void)
#ifndef COMPILE_SIMULATOR
ASSERT(readLen == sizeof(fullData));
#endif
-
int len = (GetMnemonicType() == MNEMONIC_TYPE_BIP39) ? (int)sizeof(seed) : GetCurrentAccountEntropyLen();
if (SecretCacheGetPassword() == NULL) {
printf("password is empty\n");
diff --git a/src/managers/account_manager.c b/src/managers/account_manager.c
index 81148ec..f1d22e0 100644
--- a/src/managers/account_manager.c
+++ b/src/managers/account_manager.c
@@ -139,8 +139,11 @@ int32_t CreateNewAccount(uint8_t accountIndex, const uint8_t *entropy, uint8_t e
ret = SaveCurrentAccountInfo();
CHECK_ERRCODE_RETURN_INT(ret);
ret = AccountPublicInfoSwitch(g_currentAccountIndex, password, true);
-#ifndef BTC_ONLY
+#ifdef CYPHERPUNK_VERSION
SetupZcashCache(accountIndex, password);
+#endif
+#ifdef WEB3_VERSION
+ SetupZcashSFP(accountIndex, password);
#endif
CHECK_ERRCODE_RETURN_INT(ret);
return ret;
@@ -244,8 +247,11 @@ int32_t VerifyPasswordAndLogin(uint8_t *accountIndex, const char *password)
printf("passphrase not exist, info switch\r\n");
ret = AccountPublicInfoSwitch(g_currentAccountIndex, password, false);
}
-#ifndef BTC_ONLY
- SetupZcashCache(g_currentAccountIndex, password);
+#ifdef CYPHERPUNK_VERSION
+ SetupZcashCache(*accountIndex, password);
+#endif
+#ifdef WEB3_VERSION
+ SetupZcashSFP(*accountIndex, password);
#endif
} else {
g_publicInfo.loginPasswordErrorCount++;
@@ -629,6 +635,33 @@ int32_t GetZcashSFP(uint8_t accountIndex, uint8_t* outSFP)
return ERR_ZCASH_INVALID_ACCOUNT_INDEX;
}
+int32_t SetupZcashSFP(uint8_t accountIndex, const char* password)
+{
+ ASSERT(accountIndex <= 2);
+
+ if (GetMnemonicType() == MNEMONIC_TYPE_SLIP39 || GetMnemonicType() == MNEMONIC_TYPE_TON) {
+ return SUCCESS_CODE;
+ }
+
+ uint8_t seed[SEED_LEN];
+ int len = GetMnemonicType() == MNEMONIC_TYPE_BIP39 ? sizeof(seed) : GetCurrentAccountEntropyLen();
+ int32_t ret = GetAccountSeed(accountIndex, seed, password);
+ SimpleResponse_u8 *responseSFP = calculate_zcash_seed_fingerprint(seed, len);
+ if (responseSFP->error_code != 0) {
+ ret = responseSFP->error_code;
+ printf("error: %s\r\n", responseSFP->error_message);
+ return ret;
+ }
+
+ uint8_t sfp[32];
+ memcpy_s(sfp, 32, responseSFP->data, 32);
+ free_simple_response_u8(responseSFP);
+
+ SetZcashSFP(accountIndex, sfp);
+ return ret;
+}
+
+#ifdef CYPHERPUNK_VERSION
int32_t SetupZcashCache(uint8_t accountIndex, const char* password)
{
ASSERT(accountIndex <= 2);
@@ -672,3 +705,4 @@ int32_t SetupZcashCache(uint8_t accountIndex, const char* password)
return ret;
}
#endif
+#endif
diff --git a/src/managers/account_manager.h b/src/managers/account_manager.h
index 298b5ea..7420c91 100644
--- a/src/managers/account_manager.h
+++ b/src/managers/account_manager.h
@@ -104,6 +104,9 @@ void AccountsDataCheck(void);
#ifndef BTC_ONLY
int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK);
int32_t GetZcashSFP(uint8_t accountIndex, uint8_t* outSFP);
+int32_t SetupZcashSFP(uint8_t accountIndex, const char* password);
+#ifdef CYPHERPUNK_VERSION
int32_t SetupZcashCache(uint8_t accountIndex, const char* password);
#endif
+#endif
#endif
\ No newline at end of file
diff --git a/src/managers/keystore.c b/src/managers/keystore.c
index 4431273..7c2ee1e 100644
--- a/src/managers/keystore.c
+++ b/src/managers/keystore.c
@@ -370,16 +370,16 @@ int32_t SetPassphrase(uint8_t accountIndex, const char *passphrase, const char *
strcpy_s(g_passphraseInfo[accountIndex].passphrase, PASSPHRASE_MAX_LEN, passphrase);
g_passphraseInfo[accountIndex].passphraseExist = true;
ret = TempAccountPublicInfo(accountIndex, password, true);
-#ifndef BTC_ONLY
- SetupZcashCache(accountIndex, password);
-#endif
} else {
ClearAccountPassphrase(accountIndex);
ret = AccountPublicInfoSwitch(accountIndex, password, false);
-#ifndef BTC_ONLY
- SetupZcashCache(accountIndex, password);
-#endif
}
+ #ifdef WEB3_VERSION
+ SetupZcashSFP(accountIndex, password);
+ #endif
+ #ifdef CYPHERPUNK_VERSION
+ SetupZcashCache(accountIndex, password);
+ #endif
SetPassphraseMark(passphrase[0] != '\0');
} while (0);
CLEAR_ARRAY(seed);
diff --git a/src/ui/gui_chain/gui_btc.c b/src/ui/gui_chain/gui_btc.c
index 5315149..73e31b7 100644
--- a/src/ui/gui_chain/gui_btc.c
+++ b/src/ui/gui_chain/gui_btc.c
@@ -126,7 +126,7 @@ static UREncodeResult *GuiGetSignPsbtBytesCodeData(void)
uint8_t seed[64];
int len = GetCurrentAccountSeedLen();
int ret = GetAccountSeed(GetCurrentAccountIndex(), seed, SecretCacheGetPassword());
- CHECK_ERRCODE_RETURN(ret);
+ CHECK_ERRCODE_RETURN_NULL(ret);
MultisigSignResult *result = btc_sign_multisig_psbt_bytes(g_psbtBytes, g_psbtBytesLen, seed, len, mfp, sizeof(mfp));
encodeResult = result->ur_result;
GuiMultisigTransactionSignatureSetSignStatus(result->sign_status, result->is_completed, result->psbt_hex, result->psbt_len);
diff --git a/src/ui/gui_chain/multi/gui_zcash.c b/src/ui/gui_chain/multi/gui_zcash.c
index 3e11e37..db3b417 100644
--- a/src/ui/gui_chain/multi/gui_zcash.c
+++ b/src/ui/gui_chain/multi/gui_zcash.c
@@ -33,14 +33,19 @@ void *GuiGetZcashGUIData(void)
{
CHECK_FREE_PARSE_RESULT(g_parseResult);
void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
- char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'};
uint8_t sfp[32];
- GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
GetZcashSFP(GetCurrentAccountIndex(), sfp);
PtrT_TransactionParseResult_DisplayPczt parseResult = NULL;
do {
- parseResult = parse_zcash_tx(data, ufvk, sfp);
+#ifdef WEB3_VERSION
+ parseResult = parse_zcash_tx_multi_coins(data, sfp);
+#endif
+#ifdef CYBERPUNK_VERSION
+ char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'};
+ GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
+ parseResult = parse_zcash_tx_cypherpunk(data, ufvk, sfp);
+#endif
CHECK_CHAIN_BREAK(parseResult);
g_zcashData = parseResult->data;
g_parseResult = (void *)parseResult;
@@ -300,13 +305,20 @@ static lv_obj_t* GuiZcashOverviewTo(lv_obj_t *parent, VecFFI_DisplayTo *to, lv_o
PtrT_TransactionCheckResult GuiGetZcashCheckResult(void)
{
void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
- char ufvk[ZCASH_UFVK_MAX_LEN + 1] = {0};
uint8_t sfp[32];
- GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
GetZcashSFP(GetCurrentAccountIndex(), sfp);
uint32_t zcash_account_index = 0;
MnemonicType mnemonicType = GetMnemonicType();
- return check_zcash_tx(data, ufvk, sfp, zcash_account_index, mnemonicType == MNEMONIC_TYPE_SLIP39);
+
+#ifdef WEB3_VERSION
+ char *xpub = GetCurrentAccountPublicKey(XPUB_TYPE_ZEC_TRANSPARENT_LEGACY);
+ return check_zcash_tx_multi_coins(data, xpub, sfp, zcash_account_index, mnemonicType == MNEMONIC_TYPE_SLIP39);
+#endif
+#ifdef CYBERPUNK_VERSION
+ char ufvk[ZCASH_UFVK_MAX_LEN + 1] = {0};
+ GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
+ return check_zcash_tx_cypherpunk(data, ufvk, sfp, zcash_account_index, mnemonicType == MNEMONIC_TYPE_SLIP39);
+#endif
}
UREncodeResult *GuiGetZcashSignQrCodeData(void)
diff --git a/ui_simulator/simulator_model.h b/ui_simulator/simulator_model.h
index a412900..4b41366 100644
--- a/ui_simulator/simulator_model.h
+++ b/ui_simulator/simulator_model.h
@@ -42,6 +42,8 @@ bool IsPreviousLockScreenEnable(void);
void SetLockScreen(bool enable);
void OTP_PowerOn(void);
void random_buffer(uint8_t *buf, size_t len);
+bool IsPreviousLockScreenEnable(void);
+void SetLockScreen(bool enable);
extern bool g_reboot;
Why this scored 24/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.