diff --git a/docs/protocols/ur_registrys/draft/zcash.md b/docs/protocols/ur_registrys/draft/zcash.md index 482f3f1e5..c41757a3f 100644 --- a/docs/protocols/ur_registrys/draft/zcash.md +++ b/docs/protocols/ur_registrys/draft/zcash.md @@ -31,7 +31,7 @@ The specification uses CDDL and includes `crypto-hdkey` and `crypto-key-path` sp ```cddl zcash-accounts = { - master-fingerprint: uint32, ; the master fingerprint to identify the wallet + seed-fingerprint: bytes.32, ; the seed fingerprint specified by ZIP-32 to identify the wallet accounts: [+ zcash-ufvk], ? origin: text, ; source of data, e.g., Keystone } diff --git a/rust/apps/wallets/Cargo.lock b/rust/apps/wallets/Cargo.lock index ee570d46b..c364b8090 100644 --- a/rust/apps/wallets/Cargo.lock +++ b/rust/apps/wallets/Cargo.lock @@ -1569,7 +1569,7 @@ dependencies = [ [[package]] name = "ur-parse-lib" version = "0.2.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "hex", "ur", @@ -1579,7 +1579,7 @@ dependencies = [ [[package]] name = "ur-registry" version = "0.1.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "bs58 0.4.0", "core2", diff --git a/rust/apps/wallets/src/zcash.rs b/rust/apps/wallets/src/zcash.rs index 5d308dde1..1a497bb68 100644 --- a/rust/apps/wallets/src/zcash.rs +++ b/rust/apps/wallets/src/zcash.rs @@ -23,7 +23,7 @@ impl_public_struct!(UFVKInfo { orchard_key_path: String }); -pub fn generate_sync_ur(key_infos: Vec, mfp: [u8; 4]) -> URResult { +pub fn generate_sync_ur(key_infos: Vec, seed_fingerprint: [u8; 32]) -> URResult { let keys = key_infos .iter() .map(|info| { @@ -67,6 +67,6 @@ pub fn generate_sync_ur(key_infos: Vec, mfp: [u8; 4]) -> URResult>>()?; - let accounts = ZcashAccounts::new(mfp, keys); + let accounts = ZcashAccounts::new(seed_fingerprint.to_vec(), keys); Ok(accounts) } diff --git a/rust/keystore/Cargo.lock b/rust/keystore/Cargo.lock index 02147f989..643a09e1b 100644 --- a/rust/keystore/Cargo.lock +++ b/rust/keystore/Cargo.lock @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "ur-parse-lib" version = "0.2.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "hex", "ur", @@ -1447,7 +1447,7 @@ dependencies = [ [[package]] name = "ur-registry" version = "0.1.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "bs58 0.4.0", "core2", diff --git a/rust/keystore/src/algorithms/zcash/mod.rs b/rust/keystore/src/algorithms/zcash/mod.rs index 4a3caa3f5..757b20553 100644 --- a/rust/keystore/src/algorithms/zcash/mod.rs +++ b/rust/keystore/src/algorithms/zcash/mod.rs @@ -1,4 +1,4 @@ -use alloc::string::{String, ToString}; +use alloc::{string::{String, ToString}, vec::Vec}; use ff::PrimeField; use pasta_curves::Fq; use rand_chacha::rand_core::SeedableRng; @@ -8,7 +8,7 @@ use vendor::{ orchard::keys::{SpendAuthorizingKey, SpendingKey}, zcash_keys::keys::{UnifiedAddressRequest, UnifiedSpendingKey}, zcash_protocol::consensus::{MainNetwork, MAIN_NETWORK}, - zip32::AccountId, + zip32::{fingerprint::SeedFingerprint, AccountId}, }; pub mod vendor; @@ -21,6 +21,13 @@ pub fn derive_ufvk(seed: &[u8]) -> Result { Ok(ufvk.encode(&MainNetwork)) } +pub fn calculate_seed_fingerprint(seed: &[u8]) -> Result<[u8; 32]> { + let sfp = SeedFingerprint::from_seed(seed).ok_or(KeystoreError::SeedError(format!( + "Invalid seed, cannot calculate ZIP-32 Seed Fingerprint" + )))?; + Ok(sfp.to_bytes()) +} + pub fn sign_message_orchard(seed: &[u8], alpha: [u8; 32], msg: &[u8]) -> Result<[u8; 64]> { let mut alpha = alpha; alpha.reverse(); @@ -28,7 +35,11 @@ pub fn sign_message_orchard(seed: &[u8], alpha: [u8; 32], msg: &[u8]) -> Result< let rng = ChaCha8Rng::from_seed(rng_seed); let osk = SpendingKey::from_zip32_seed(seed, 133, AccountId::ZERO).unwrap(); let osak = SpendAuthorizingKey::from(&osk); - let randm = Fq::from_repr(alpha).into_option().ok_or(KeystoreError::InvalidDataError(format!("invalid orchard alpha")))?; + let randm = Fq::from_repr(alpha) + .into_option() + .ok_or(KeystoreError::InvalidDataError(format!( + "invalid orchard alpha" + )))?; let sig = osak.randomize(&randm).sign(rng, &msg); let bytes = <[u8; 64]>::from(&sig); Ok(bytes) diff --git a/rust/rust_c/Cargo.lock b/rust/rust_c/Cargo.lock index 07dc62201..1eb831477 100644 --- a/rust/rust_c/Cargo.lock +++ b/rust/rust_c/Cargo.lock @@ -3278,7 +3278,7 @@ dependencies = [ [[package]] name = "ur-parse-lib" version = "0.2.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "hex", "ur", @@ -3288,7 +3288,7 @@ dependencies = [ [[package]] name = "ur-registry" version = "0.1.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "bs58 0.4.0", "core2", diff --git a/rust/rust_c/src/wallet/src/multi_coins_wallet/src/zcash.rs b/rust/rust_c/src/wallet/src/multi_coins_wallet/src/zcash.rs index 56586e774..1fc0a075e 100644 --- a/rust/rust_c/src/wallet/src/multi_coins_wallet/src/zcash.rs +++ b/rust/rust_c/src/wallet/src/multi_coins_wallet/src/zcash.rs @@ -15,20 +15,20 @@ use third_party::ur_registry::zcash::zcash_accounts::ZcashAccounts; #[no_mangle] pub extern "C" fn get_connect_zcash_wallet_ur( - mfp: PtrBytes, - mfp_len: u32, + seed_fingerprint: PtrBytes, + seed_fingerprint_len: u32, zcash_keys: Ptr>, ) -> *mut UREncodeResult { - if mfp_len != 4 { + if seed_fingerprint_len != 32 { return UREncodeResult::from(URError::UrEncodeError(format!( - "master fingerprint length must be 4, current is {}", - mfp_len + "zip-32 seed fingerprint length must be 32, current is {}", + seed_fingerprint_len ))) .c_ptr(); } - let mfp = extract_array!(mfp, u8, mfp_len); - let mfp = match <[u8; 4]>::try_from(mfp) { - Ok(mfp) => mfp, + let seed_fingerprint = extract_array!(seed_fingerprint, u8, seed_fingerprint_len); + let seed_fingerprint = match <[u8; 32]>::try_from(seed_fingerprint) { + Ok(seed_fingerprint) => seed_fingerprint, Err(e) => return UREncodeResult::from(URError::UrEncodeError(e.to_string())).c_ptr(), }; unsafe { @@ -44,7 +44,7 @@ pub extern "C" fn get_connect_zcash_wallet_ur( ) }) .collect(); - let result = generate_sync_ur(ufvks, mfp); + let result = generate_sync_ur(ufvks, seed_fingerprint); match result.map(|v| v.try_into()) { Ok(v) => match v { Ok(data) => UREncodeResult::encode( diff --git a/rust/rust_c/src/zcash/src/lib.rs b/rust/rust_c/src/zcash/src/lib.rs index d54e34f29..5f255072f 100644 --- a/rust/rust_c/src/zcash/src/lib.rs +++ b/rust/rust_c/src/zcash/src/lib.rs @@ -1,15 +1,17 @@ #![no_std] +extern crate alloc; use core::slice; +use alloc::boxed::Box; +use app_zcash::get_address; use common_rust_c::{ structs::{Response, SimpleResponse}, types::{PtrBytes, PtrString}, utils::{convert_c_char, recover_c_char}, }; -use keystore::algorithms::zcash::{self, derive_ufvk}; +use keystore::algorithms::zcash::{self, calculate_seed_fingerprint, derive_ufvk}; use third_party::cty::c_char; -use app_zcash::get_address; #[no_mangle] pub extern "C" fn derive_zcash_ufvk(seed: PtrBytes, seed_len: u32) -> *mut SimpleResponse { @@ -22,11 +24,23 @@ pub extern "C" fn derive_zcash_ufvk(seed: PtrBytes, seed_len: u32) -> *mut Simpl } #[no_mangle] -pub extern "C" fn generate_zcash_default_address(ufvk_text: PtrString) -> *mut SimpleResponse { +pub extern "C" fn calculate_zcash_seed_fingerprint(seed: PtrBytes, seed_len: u32) -> *mut SimpleResponse { + let seed = unsafe { slice::from_raw_parts(seed, seed_len as usize) }; + let sfp = calculate_seed_fingerprint(seed); + match sfp { + Ok(bytes) => SimpleResponse::success(Box::into_raw(Box::new(bytes)) as *mut u8).simple_c_ptr(), + Err(e) => SimpleResponse::from(e).simple_c_ptr(), + } +} + +#[no_mangle] +pub extern "C" fn generate_zcash_default_address( + ufvk_text: PtrString, +) -> *mut SimpleResponse { let ufvk_text = recover_c_char(ufvk_text); let address = get_address(&ufvk_text); match address { Ok(text) => SimpleResponse::success(convert_c_char(text)).simple_c_ptr(), Err(e) => SimpleResponse::from(e).simple_c_ptr(), } -} \ No newline at end of file +} diff --git a/rust/third_party/Cargo.lock b/rust/third_party/Cargo.lock index 0ddcbeba1..41b7d9ea4 100644 --- a/rust/third_party/Cargo.lock +++ b/rust/third_party/Cargo.lock @@ -1094,7 +1094,7 @@ dependencies = [ [[package]] name = "ur-parse-lib" version = "0.2.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "hex", "ur", @@ -1104,7 +1104,7 @@ dependencies = [ [[package]] name = "ur-registry" version = "0.1.0" -source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.33-alpha1#42c7afd389cdc8d2c47a77afaaabb89e196a0192" +source = "git+https://git@github.com/KeystoneHQ/keystone-sdk-rust.git?tag=0.0.36-alpha0#2996f57ad2fce0132cfc0258a3981749d1bf9969" dependencies = [ "bs58", "core2", diff --git a/rust/third_party/Cargo.toml b/rust/third_party/Cargo.toml index 16d50fc8c..279aa9720 100644 --- a/rust/third_party/Cargo.toml +++ b/rust/third_party/Cargo.toml @@ -20,8 +20,8 @@ rsa = { version = "0.8.2", default-features = false } sha1 = { version = "0.10.5", default-features = false } cty = "0.2.2" cstr_core = "0.2.6" -ur-registry = { git = "https://git@github.com/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.33-alpha1" } -ur-parse-lib = { git = "https://git@github.com/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.33-alpha1" } +ur-registry = { git = "https://git@github.com/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.36-alpha0" } +ur-parse-lib = { git = "https://git@github.com/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.36-alpha0" } ed25519-bip32-core = { version = "0.1.1", default-features = false } cryptoxide = "0.4" itertools = { version = "0.10.5", default-features = false, features = [ diff --git a/src/managers/account_manager.c b/src/managers/account_manager.c index c934b35e5..0433d4a84 100644 --- a/src/managers/account_manager.c +++ b/src/managers/account_manager.c @@ -140,7 +140,6 @@ int32_t CreateNewAccount(uint8_t accountIndex, const uint8_t *entropy, uint8_t e return ret; } - int32_t CreateNewSlip39Account(uint8_t accountIndex, const uint8_t *ems, const uint8_t *entropy, uint8_t entropyLen, const char *password, uint16_t id, uint8_t ie) { ASSERT(accountIndex <= 2); @@ -559,19 +558,23 @@ int32_t CreateNewTonAccount(uint8_t accountIndex, const char *mnemonic, const ch return ret; } -void SetZcashUFVK(uint8_t accountIndex, const char* ufvk) { +static void SetZcashUFVK(uint8_t accountIndex, const char* ufvk, const uint8_t* seedFingerprint) { ASSERT(accountIndex <= 2); g_zcashUFVKcache.accountIndex = accountIndex; memset_s(g_zcashUFVKcache.ufvkCache, ZCASH_UFVK_MAX_LEN, '\0', ZCASH_UFVK_MAX_LEN); strcpy_s(g_zcashUFVKcache.ufvkCache, ZCASH_UFVK_MAX_LEN, ufvk); + + memset_s(g_zcashUFVKcache.seedFingerprint, 32, 0, 32); + memcpy_s(g_zcashUFVKcache.seedFingerprint, 32, seedFingerprint, 32); printf("SetZcashUFVK, %s\r\n", g_zcashUFVKcache.ufvkCache); } -int32_t GetZcashUFVK(uint8_t accountIndex, char* output) { +int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK, uint8_t* outSFP) { ASSERT(accountIndex <= 2); if (g_zcashUFVKcache.accountIndex == accountIndex) { - strcpy_s(output, ZCASH_UFVK_MAX_LEN, g_zcashUFVKcache.ufvkCache); + strcpy_s(outUFVK, ZCASH_UFVK_MAX_LEN, g_zcashUFVKcache.ufvkCache); + memcpy_s(outSFP, 32, g_zcashUFVKcache.seedFingerprint, 32); return SUCCESS_CODE; } return ERR_ZCASH_INVALID_ACCOUNT_INDEX; @@ -579,8 +582,10 @@ int32_t GetZcashUFVK(uint8_t accountIndex, char* output) { int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password) { ASSERT(accountIndex <= 2); + uint8_t seed[SEED_LEN]; int32_t ret = GetAccountSeed(accountIndex, &seed, password); + SimpleResponse_c_char *response = derive_zcash_ufvk(seed, SEED_LEN); if (response->error_code != 0) { @@ -588,8 +593,23 @@ int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password) { printf("error: %s\r\n", response->error_message); return ret; } - printf("CalculateZcashUFVK: %s\r\n", response->data); - SetZcashUFVK(accountIndex, response->data); + + char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'}; + strcpy_s(ufvk, ZCASH_UFVK_MAX_LEN, response->data); + free_simple_response_c_char(response); + + SimpleResponse_u8 *responseSFP = calculate_zcash_seed_fingerprint(seed, SEED_LEN); + if (responseSFP->error_code != 0) + { + ret = response->error_code; + printf("error: %s\r\n", response->error_message); + return ret; + } + + uint8_t sfp[32]; + memcpy_s(sfp, 32, responseSFP->data, 32); + free_simple_response_u8(responseSFP); + + SetZcashUFVK(accountIndex, ufvk, sfp); } #endif - diff --git a/src/managers/account_manager.h b/src/managers/account_manager.h index 4fc62d809..583891494 100644 --- a/src/managers/account_manager.h +++ b/src/managers/account_manager.h @@ -49,6 +49,7 @@ typedef struct { typedef struct { uint8_t accountIndex; char ufvkCache[ZCASH_UFVK_MAX_LEN + 1]; + uint8_t seedFingerprint[32]; } ZcashUFVKCache_t; int32_t AccountManagerInit(void); @@ -97,7 +98,7 @@ uint16_t GetSlip39Id(void); uint8_t GetSlip39Ie(void); void AccountsDataCheck(void); -int32_t GetZcashUFVK(uint8_t accountIndex, char* output); +int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK, uint8_t* outSFP); int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password); #endif \ No newline at end of file diff --git a/src/ui/gui_widgets/general/gui_standard_receive_widgets.c b/src/ui/gui_widgets/general/gui_standard_receive_widgets.c index 88739bb07..b31a69709 100644 --- a/src/ui/gui_widgets/general/gui_standard_receive_widgets.c +++ b/src/ui/gui_widgets/general/gui_standard_receive_widgets.c @@ -206,7 +206,6 @@ static void UpdateConfirmIndexBtn(void) UpdateConfirmBtn(); } - static void RefreshSwitchAddress(void) { AddressDataItem_t addressDataItem; @@ -931,8 +930,9 @@ static void ModelGetAddress(uint32_t index, AddressDataItem_t *item) break; } case HOME_WALLET_CARD_ZEC: { - char ufvk[ZCASH_UFVK_MAX_LEN] = {0}; - GetZcashUFVK(GetCurrentAccountIndex(), ufvk); + char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'}; + uint8_t sfp[32]; + GetZcashUFVK(GetCurrentAccountIndex(), ufvk, sfp); result = generate_zcash_default_address(ufvk); break; } diff --git a/src/ui/gui_widgets/gui_connect_wallet_widgets.c b/src/ui/gui_widgets/gui_connect_wallet_widgets.c index 5bc80175d..873f675d9 100644 --- a/src/ui/gui_widgets/gui_connect_wallet_widgets.c +++ b/src/ui/gui_widgets/gui_connect_wallet_widgets.c @@ -1211,14 +1211,15 @@ UREncodeResult *GuiGetZecData(void) keys->data = data; keys->size = 1; char ufvk[384] = {'\0'}; - GetZcashUFVK(GetCurrentAccountIndex(), ufvk); + uint8_t sfp[32]; + GetZcashUFVK(GetCurrentAccountIndex(), ufvk, sfp); data[0].key_text = ufvk; data[0].key_name = GetWalletName(); char transparent_path[24] = "m/44'/133'/0'"; char orchard_path[24] = "m/32'/133'/0'"; data[0].transparent_key_path = transparent_path; data[0].orchard_key_path = orchard_path; - return get_connect_zcash_wallet_ur(mfp, mfp == NULL ? 0 : 4, keys); + return get_connect_zcash_wallet_ur(sfp, 32, keys); } void GuiPrepareArConnectWalletView(void)