@@ -12,7 +12,9 @@ use masp_primitives::transaction::components::sapling::builder::{
1212 SpendBuildParams , StoredBuildParams ,
1313} ;
1414use masp_primitives:: transaction:: components:: sapling:: fees:: InputView ;
15- use masp_primitives:: zip32:: { ExtendedFullViewingKey , ExtendedKey } ;
15+ use masp_primitives:: zip32:: {
16+ ExtendedFullViewingKey , ExtendedKey , PseudoExtendedKey ,
17+ } ;
1618use namada_sdk:: address:: { Address , ImplicitAddress } ;
1719use namada_sdk:: args:: TxBecomeValidator ;
1820use namada_sdk:: collections:: { HashMap , HashSet } ;
@@ -43,6 +45,22 @@ use crate::wallet::{
4345 gen_validator_keys, read_and_confirm_encryption_password, WalletTransport ,
4446} ;
4547
48+ // Maximum number of spend description randomness parameters that can be
49+ // generated on the hardware wallet. It is hard to compute the exact required
50+ // number because a given MASP source could be distributed amongst several
51+ // notes.
52+ const MAX_HW_SPEND : usize = 10 ;
53+ // Maximum number of convert description randomness parameters that can be
54+ // generated on the hardware wallet. It is hard to compute the exact required
55+ // number because the number of conversions that are used depends on the
56+ // protocol's current state.
57+ const MAX_HW_CONVERT : usize = 10 ;
58+ // Maximum number of output description randomness parameters that can be
59+ // generated on the hardware wallet. It is hard to compute the exact required
60+ // number because the number of outputs depends on the number of dummy outputs
61+ // introduced.
62+ const MAX_HW_OUTPUT : usize = 10 ;
63+
4664/// Wrapper around `signing::aux_signing_data` that stores the optional
4765/// disposable address to the wallet
4866pub async fn aux_signing_data (
@@ -862,24 +880,25 @@ impl sapling::MapAuth<sapling::Authorized, sapling::Authorized>
862880// it does on the software client.
863881async fn augment_masp_hardware_keys (
864882 namada : & impl Namada ,
865- args : & mut args:: TxShieldedTransfer ,
883+ args : & args:: Tx ,
884+ sources : impl Iterator < Item = & mut PseudoExtendedKey > ,
866885) -> Result < HashMap < String , ExtendedViewingKey > , error:: Error > {
867886 // Records the shielded keys that are on the hardware wallet
868887 let mut shielded_hw_keys = HashMap :: new ( ) ;
869888 // Construct the build parameters that parameterized the Transaction
870889 // authorizations
871- if args. tx . use_device {
872- let transport = WalletTransport :: from_arg ( args. tx . device_transport ) ;
890+ if args. use_device {
891+ let transport = WalletTransport :: from_arg ( args. device_transport ) ;
873892 let app = NamadaApp :: new ( transport) ;
874893 let wallet = namada. wallet ( ) . await ;
875894 // Augment the pseudo spending key with a proof authorization key
876- for data in & mut args . data {
895+ for source in sources {
877896 // Only attempt an augmentation if proof authorization is not there
878- if data . source . to_spending_key ( ) . is_none ( ) {
897+ if source. to_spending_key ( ) . is_none ( ) {
879898 // First find the derivation path corresponding to this viewing
880899 // key
881900 let viewing_key =
882- ExtendedViewingKey :: from ( data . source . to_viewing_key ( ) ) ;
901+ ExtendedViewingKey :: from ( source. to_viewing_key ( ) ) ;
883902 let path = wallet
884903 . find_path_by_viewing_key ( & viewing_key)
885904 . map_err ( |err| {
@@ -950,21 +969,18 @@ async fn augment_masp_hardware_keys(
950969 ) )
951970 } ) ?;
952971 // Augment the pseudo spending key
953- data. source . augment_proof_generation_key ( pgk) . map_err (
954- |_| {
955- error:: Error :: Other (
956- "Proof generation key in response from the \
957- hardware wallet does not correspond to stored \
958- viewing key."
959- . to_string ( ) ,
960- )
961- } ,
962- ) ?;
972+ source. augment_proof_generation_key ( pgk) . map_err ( |_| {
973+ error:: Error :: Other (
974+ "Proof generation key in response from the hardware \
975+ wallet does not correspond to stored viewing key."
976+ . to_string ( ) ,
977+ )
978+ } ) ?;
963979 // Finally, augment an incorrect spend authorization key just to
964980 // make sure that the Transaction is built.
965- data . source . augment_spend_authorizing_key_unchecked (
966- PrivateKey ( jubjub:: Fr :: default ( ) ) ,
967- ) ;
981+ source. augment_spend_authorizing_key_unchecked ( PrivateKey (
982+ jubjub:: Fr :: default ( ) ,
983+ ) ) ;
968984 shielded_hw_keys. insert ( path. path , viewing_key) ;
969985 }
970986 }
@@ -977,12 +993,15 @@ async fn augment_masp_hardware_keys(
977993// If the hardware wallet is beig used, use it to generate the random build
978994// parameters for the spend, convert, and output descriptions.
979995async fn generate_masp_build_params (
980- args : & args:: TxShieldedTransfer ,
996+ spend_len : usize ,
997+ convert_len : usize ,
998+ output_len : usize ,
999+ args : & args:: Tx ,
9811000) -> Result < Box < dyn BuildParams > , error:: Error > {
9821001 // Construct the build parameters that parameterized the Transaction
9831002 // authorizations
984- if args. tx . use_device {
985- let transport = WalletTransport :: from_arg ( args. tx . device_transport ) ;
1003+ if args. use_device {
1004+ let transport = WalletTransport :: from_arg ( args. device_transport ) ;
9861005 let app = NamadaApp :: new ( transport) ;
9871006 // Clear hardware wallet randomness buffers
9881007 app. clean_randomness_buffers ( ) . await . map_err ( |err| {
@@ -993,16 +1012,6 @@ async fn generate_masp_build_params(
9931012 } ) ?;
9941013 // Get randomness to aid in construction of various descriptors
9951014 let mut bparams = StoredBuildParams :: default ( ) ;
996- // Number of spend descriptions is the number of transfers
997- let spend_len = args. data . len ( ) ;
998- // Number of convert description is assumed to be double the number of
999- // transfers. This is because each spend description might first be
1000- // converted to epoch 0 before going to the intended epoch.
1001- let convert_len = args. data . len ( ) * 2 ;
1002- // Number of output descriptions is assumed to be double the number of
1003- // transfers. This is because there may be change from each output
1004- // that's destined for the sender.
1005- let output_len = args. data . len ( ) * 2 ;
10061015 for _ in 0 ..spend_len {
10071016 let spend_randomness = app
10081017 . get_spend_randomness ( )
@@ -1011,7 +1020,6 @@ async fn generate_masp_build_params(
10111020 bparams. spend_params . push ( SpendBuildParams {
10121021 rcv : jubjub:: Fr :: from_bytes ( & spend_randomness. rcv ) . unwrap ( ) ,
10131022 alpha : jubjub:: Fr :: from_bytes ( & spend_randomness. alpha ) . unwrap ( ) ,
1014- ..SpendBuildParams :: default ( )
10151023 } ) ;
10161024 }
10171025 for _ in 0 ..convert_len {
@@ -1143,9 +1151,20 @@ pub async fn submit_shielded_transfer(
11431151 namada : & impl Namada ,
11441152 mut args : args:: TxShieldedTransfer ,
11451153) -> Result < ( ) , error:: Error > {
1154+ let sources = args
1155+ . data
1156+ . iter_mut ( )
1157+ . map ( |x| & mut x. source )
1158+ . chain ( args. gas_spending_keys . iter_mut ( ) ) ;
11461159 let shielded_hw_keys =
1147- augment_masp_hardware_keys ( namada, & mut args) . await ?;
1148- let mut bparams = generate_masp_build_params ( & args) . await ?;
1160+ augment_masp_hardware_keys ( namada, & args. tx , sources) . await ?;
1161+ let mut bparams = generate_masp_build_params (
1162+ MAX_HW_SPEND ,
1163+ MAX_HW_CONVERT ,
1164+ MAX_HW_OUTPUT ,
1165+ & args. tx ,
1166+ )
1167+ . await ?;
11491168 let ( mut tx, signing_data) =
11501169 args. clone ( ) . build ( namada, & mut bparams) . await ?;
11511170
@@ -1165,7 +1184,15 @@ pub async fn submit_shielding_transfer(
11651184) -> Result < ( ) , error:: Error > {
11661185 // Repeat once if the tx fails on a crossover of an epoch
11671186 for _ in 0 ..2 {
1168- let ( tx, signing_data, tx_epoch) = args. clone ( ) . build ( namada) . await ?;
1187+ let mut bparams = generate_masp_build_params (
1188+ MAX_HW_SPEND ,
1189+ MAX_HW_CONVERT ,
1190+ MAX_HW_OUTPUT ,
1191+ & args. tx ,
1192+ )
1193+ . await ?;
1194+ let ( tx, signing_data, tx_epoch) =
1195+ args. clone ( ) . build ( namada, & mut bparams) . await ?;
11691196
11701197 if args. tx . dump_tx {
11711198 tx:: dump_tx ( namada. io ( ) , & args. tx , tx) ;
@@ -1217,13 +1244,26 @@ pub async fn submit_shielding_transfer(
12171244
12181245pub async fn submit_unshielding_transfer (
12191246 namada : & impl Namada ,
1220- args : args:: TxUnshieldingTransfer ,
1247+ mut args : args:: TxUnshieldingTransfer ,
12211248) -> Result < ( ) , error:: Error > {
1222- let ( mut tx, signing_data) = args. clone ( ) . build ( namada) . await ?;
1249+ let sources = std:: iter:: once ( & mut args. source )
1250+ . chain ( args. gas_spending_keys . iter_mut ( ) ) ;
1251+ let shielded_hw_keys =
1252+ augment_masp_hardware_keys ( namada, & args. tx , sources) . await ?;
1253+ let mut bparams = generate_masp_build_params (
1254+ MAX_HW_SPEND ,
1255+ MAX_HW_CONVERT ,
1256+ MAX_HW_OUTPUT ,
1257+ & args. tx ,
1258+ )
1259+ . await ?;
1260+ let ( mut tx, signing_data) =
1261+ args. clone ( ) . build ( namada, & mut bparams) . await ?;
12231262
12241263 if args. tx . dump_tx {
12251264 tx:: dump_tx ( namada. io ( ) , & args. tx , tx) ;
12261265 } else {
1266+ masp_sign ( & mut tx, & args. tx , & signing_data, shielded_hw_keys) . await ?;
12271267 sign ( namada, & mut tx, & args. tx , signing_data) . await ?;
12281268 namada. submit ( tx, & args. tx ) . await ?;
12291269 }
@@ -1232,16 +1272,31 @@ pub async fn submit_unshielding_transfer(
12321272
12331273pub async fn submit_ibc_transfer < N : Namada > (
12341274 namada : & N ,
1235- args : args:: TxIbcTransfer ,
1275+ mut args : args:: TxIbcTransfer ,
12361276) -> Result < ( ) , error:: Error >
12371277where
12381278 <N :: Client as namada_sdk:: io:: Client >:: Error : std:: fmt:: Display ,
12391279{
1240- let ( tx, signing_data, _) = args. build ( namada) . await ?;
1280+ let sources = args
1281+ . source
1282+ . spending_key_mut ( )
1283+ . into_iter ( )
1284+ . chain ( args. gas_spending_keys . iter_mut ( ) ) ;
1285+ let shielded_hw_keys =
1286+ augment_masp_hardware_keys ( namada, & args. tx , sources) . await ?;
1287+ let mut bparams = generate_masp_build_params (
1288+ MAX_HW_SPEND ,
1289+ MAX_HW_CONVERT ,
1290+ MAX_HW_OUTPUT ,
1291+ & args. tx ,
1292+ )
1293+ . await ?;
1294+ let ( mut tx, signing_data, _) = args. build ( namada, & mut bparams) . await ?;
12411295
12421296 if args. tx . dump_tx {
12431297 tx:: dump_tx ( namada. io ( ) , & args. tx , tx) ;
12441298 } else {
1299+ masp_sign ( & mut tx, & args. tx , & signing_data, shielded_hw_keys) . await ?;
12451300 batch_opt_reveal_pk_and_submit (
12461301 namada,
12471302 & args. tx ,
0 commit comments