11use zcash_address:: unified:: { Encoding , Fvk , Ufvk } ;
22
33use alloc:: format;
4- use ledger_device_sdk:: info;
4+ use ledger_device_sdk:: log :: { error , info} ;
55use ledger_device_sdk:: io:: Comm ;
66
77use crate :: app_ui:: address:: { ui_display_orchard_fvk, ui_display_ufvk} ;
8+ use crate :: consts:: { UNHARDENED_MASK , ZCASH_BIP44_COIN_TYPE } ;
89use crate :: utils:: { HexSlice , encode_string_response} ;
910use crate :: zip32:: { derive_orchard_fvk, derive_transparent_account_pubkey, orchard_network} ;
1011use crate :: {
@@ -15,6 +16,16 @@ use crate::{
1516
1617const VK_RESPONSE_CHUNK_LEN : usize = 255 ;
1718
19+ fn check_transparent_vk_path ( path : & Bip32Path ) -> bool {
20+ const HARDENED : u32 = 0x8000_0000 ;
21+ const BIP44_PURPOSE : u32 = 44 ;
22+ let p = path. as_slice ( ) ;
23+ p. len ( ) == 3
24+ && ( p[ 0 ] & UNHARDENED_MASK ) == BIP44_PURPOSE
25+ && ( p[ 1 ] & UNHARDENED_MASK ) == ZCASH_BIP44_COIN_TYPE
26+ && p[ 2 ] & HARDENED != 0
27+ }
28+
1829fn parse_vk_paths ( data : & [ u8 ] , mode : P2VkMode ) -> Result < ( Bip32Path , Option < Bip32Path > ) , AppSW > {
1930 match mode {
2031 P2VkMode :: OrchardFvk => Ok ( ( Bip32Path :: try_from ( data) ?, None ) ) ,
@@ -63,6 +74,19 @@ pub fn handler_get_vk(
6374 ctx. vk_response = None ;
6475
6576 let ( path, transparent_path) = parse_vk_paths ( data, mode) ?;
77+
78+ if let P2VkMode :: Ufvk = mode {
79+ let t_path = transparent_path. as_ref ( ) . ok_or ( AppSW :: WrongApduLength ) ?;
80+ if !check_transparent_vk_path ( t_path) {
81+ error ! ( "Transparent VK path is not a valid account-level BIP44 path" ) ;
82+ return Err ( AppSW :: IncorrectData ) ;
83+ }
84+ if ( path. as_slice ( ) [ 2 ] & UNHARDENED_MASK ) != ( t_path. as_slice ( ) [ 2 ] & UNHARDENED_MASK ) {
85+ error ! ( "Orchard and transparent VK paths must have matching accounts" ) ;
86+ return Err ( AppSW :: IncorrectData ) ;
87+ }
88+ }
89+
6690 let orchard_fvk = derive_orchard_fvk ( & path) ?;
6791
6892 let response_bytes = match mode {
0 commit comments