diff --git a/src/carrot_core/account.cpp b/src/carrot_core/account.cpp index f0b3433d5..ed6a54077 100644 --- a/src/carrot_core/account.cpp +++ b/src/carrot_core/account.cpp @@ -337,7 +337,7 @@ void carrot_and_legacy_account::set_keys(const cryptonote::account_keys& keys, b } //---------------------------------------------------------------------------------------------------------------------- void carrot_and_legacy_account::create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key) -{ +{ // top level keys m_keys.s_master = crypto::null_skey; make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend); @@ -359,7 +359,17 @@ void carrot_and_legacy_account::create_from_svb_key(const cryptonote::account_pu k_view_incoming_dev.view_key_scalar_mult_ed25519(crypto::get_G(), m_keys.m_carrot_main_address.m_view_public_key ); - + + // Store fields for Carrot + m_keys.m_spend_secret_key = crypto::null_skey; + m_keys.m_view_secret_key = crypto::null_skey; + m_keys.m_account_address = {crypto::null_pkey, crypto::null_pkey, false}; + + // Update ALL addresses to be Carrot-only + m_keys.m_carrot_account_address.m_is_carrot = true; + m_keys.m_carrot_main_address.m_is_carrot = true; + + // Set the default derive type for addresses this->default_derive_type = AddressDeriveType::Carrot; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp index c7ad82eec..3b4b72281 100644 --- a/src/cryptonote_basic/account.cpp +++ b/src/cryptonote_basic/account.cpp @@ -89,12 +89,24 @@ DISABLE_VS_WARNINGS(4244 4345) void account_keys::xor_with_key_stream(const crypto::chacha_key &key) { // encrypt a large enough byte stream with chacha20 - epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size())); + epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (8 + m_multisig_keys.size())); const char *ptr = key_stream.data(); for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) m_spend_secret_key.data[i] ^= *ptr++; for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) m_view_secret_key.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + s_master.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + k_prove_spend.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + s_view_balance.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + k_view_incoming.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + k_generate_image.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + s_generate_address.data[i] ^= *ptr++; for (crypto::secret_key &k: m_multisig_keys) { for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) @@ -116,11 +128,15 @@ DISABLE_VS_WARNINGS(4244 4345) void account_keys::encrypt_viewkey(const crypto::chacha_key &key) { // encrypt a large enough byte stream with chacha20 - epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 2); + epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 3); const char *ptr = key_stream.data(); ptr += sizeof(crypto::secret_key); for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) m_view_secret_key.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + s_view_balance.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + k_view_incoming.data[i] ^= *ptr++; } //----------------------------------------------------------------- void account_keys::decrypt_viewkey(const crypto::chacha_key &key) diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h index b6e0b5709..8dcfd61a3 100644 --- a/src/cryptonote_basic/account.h +++ b/src/cryptonote_basic/account.h @@ -75,6 +75,11 @@ namespace cryptonote KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys) const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}}; KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv) + if (m_account_address.m_spend_public_key == crypto::null_pkey) { + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(s_view_balance) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(k_view_incoming) + KV_SERIALIZE(m_carrot_account_address) + } END_KV_SERIALIZE_MAP() void encrypt(const crypto::chacha_key &key); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ba01e8cf5..4e91f5ef2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5464,14 +5464,31 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st } const cryptonote::account_keys& keys = m_account.get_keys(); hw::device &hwdev = m_account.get_device(); - r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + if (m_watch_only) { + + // Check to see if this is a Carrot SVB wallet + crypto::secret_key kv_recomputed; + carrot::make_carrot_viewincoming_key(keys.s_view_balance, kv_recomputed); + THROW_WALLET_EXCEPTION_IF(keys.k_view_incoming != kv_recomputed, error::wallet_internal_error, "cannot compute viable wallet"); + + // assume Carrot SVB wallet + m_account.create_from_svb_key(keys.m_carrot_account_address, keys.s_view_balance); + + // Now verify that the account address has a public view key that matches k_view_incoming + r = r && hwdev.verify_keys(keys.k_view_incoming, keys.m_carrot_main_address.m_view_public_key); + + } else { + // Assume normal wallet + r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + } if (!m_watch_only && !m_multisig && hwdev.device_protocol() != hw::device::PROTOCOL_COLD && !m_is_background_wallet) r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); if (r) { - m_account.set_carrot_keys(); + if (!m_watch_only) + m_account.set_carrot_keys(); if (!m_is_background_wallet) setup_keys(password); @@ -5561,7 +5578,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip encrypted_secret_keys = field_encrypted_secret_keys; } - cryptonote::account_base account_data_check; + carrot::carrot_and_legacy_account account_data_check; r = epee::serialization::load_t_from_binary(account_data_check, account_data); @@ -5569,7 +5586,14 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip account_data_check.decrypt_keys(key); const cryptonote::account_keys& keys = account_data_check.get_keys(); - r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + if (no_spend_key) { + // assume Carrot SVB wallet + account_data_check.create_from_svb_key(keys.m_carrot_account_address, keys.s_view_balance); + // Now verify that the account address has a public view key that matches k_view_incoming + r = r && hwdev.verify_keys(keys.k_view_incoming, keys.m_carrot_main_address.m_view_public_key); + } else { + r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + } if(!no_spend_key) r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); spend_key_out = (!no_spend_key && r) ? keys.m_spend_secret_key : crypto::null_skey; @@ -6826,10 +6850,17 @@ void wallet2::load_wallet_cache(const bool use_fs, const std::string& cache_buf) ar >> *this; } } - THROW_WALLET_EXCEPTION_IF( - m_account_public_address.m_spend_public_key != m_account.get_keys().m_account_address.m_spend_public_key || - m_account_public_address.m_view_public_key != m_account.get_keys().m_account_address.m_view_public_key, - error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); + if (m_watch_only) { + THROW_WALLET_EXCEPTION_IF( + m_account_public_address.m_spend_public_key != m_account.get_keys().m_carrot_main_address.m_spend_public_key || + m_account_public_address.m_view_public_key != m_account.get_keys().m_carrot_main_address.m_view_public_key, + error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); + } else { + THROW_WALLET_EXCEPTION_IF( + m_account_public_address.m_spend_public_key != m_account.get_keys().m_account_address.m_spend_public_key || + m_account_public_address.m_view_public_key != m_account.get_keys().m_account_address.m_view_public_key, + error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); + } } } //----------------------------------------------------------------------------------------------------