What changed, and why it matters
This commit adds two new read-only options to the wallet's remote procedure call (RPC) interface so users can request their public view key and public spend key. Public keys are meant to be shared openly and are not secrets, so exposing them through an existing authenticated API is not a security issue. The change also includes tests verifying the new behavior.
No security action required. This is a benign feature addition. Routine review and merge are appropriate.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch extends the wallet_rpc_server.cpp query_key handler to recognize key_type values ‘public_view_key’ and ‘public_spend_key’, returning the wallet’s m_view_public_key and m_spend_public_key as hex strings. These are public components of the Monero stealth address and are already derivable from the wallet’s standard address. Functional tests in cold_signing.py and wallet.py are updated to assert the returned values match expected public keys. No secret material is newly exposed, no access controls are changed, and no vulnerability is introduced.
Changed components
src/wallet/wallet_rpc_server.cpptests/functional_tests/cold_signing.pytests/functional_tests/wallet.pyInspect captured patch +17 / −0
### src/wallet/wallet_rpc_server.cpp
@@ -2453,6 +2453,16 @@ namespace tools
epee::wipeable_string key = epee::to_hex::wipeable_string(m_wallet->get_account().get_keys().m_spend_secret_key);
res.key = std::string(key.data(), key.size());
}
+ else if(req.key_type.compare("public_view_key") == 0)
+ {
+ epee::wipeable_string key = epee::to_hex::wipeable_string(m_wallet->get_account().get_keys().m_account_address.m_view_public_key);
+ res.key = std::string(key.data(), key.size());
+ }
+ else if(req.key_type.compare("public_spend_key") == 0)
+ {
+ epee::wipeable_string key = epee::to_hex::wipeable_string(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key);
+ res.key = std::string(key.data(), key.size());
+ }
else
{
er.message = "key_type " + req.key_type + " not found";
### tests/functional_tests/cold_signing.py
@@ -87,6 +87,9 @@ def create(self, idx):
except: ok = True
assert ok
assert self.cold_wallet.query_key("view_key").key == view_key
+ assert self.hot_wallet.query_key("public_view_key").key == self.cold_wallet.query_key("public_view_key").key
+ assert self.cold_wallet.query_key("public_spend_key").key == '1b3bd040020d3712ab84992b773d0a965134eb2df0392fb84af95de8a17be2ab'
+ assert self.hot_wallet.query_key("public_spend_key").key == self.cold_wallet.query_key("public_spend_key").key
assert self.cold_wallet.get_address().address == self.hot_wallet.get_address().address
assert self.cold_wallet.get_address().address == STANDARD_ADDRESS
### tests/functional_tests/wallet.py
@@ -101,6 +101,10 @@ def check_keys(self):
assert res.key == '49774391fa5e8d249fc2c5b45dadef13534bf2483dede880dac88f061e809100'
res = wallet.query_key('spend_key')
assert res.key == '148d78d2aba7dbca5cd8f6abcfb0b3c009ffbdbea1ff373d50ed94d78286640e'
+ res = wallet.query_key('public_view_key')
+ assert res.key == '231c9bf8341c6a870d92e3fb98063a90a355fb8dbf74a8561b9d7f9273247e99'
+ res = wallet.query_key('public_spend_key')
+ assert res.key == '1b3bd040020d3712ab84992b773d0a965134eb2df0392fb84af95de8a17be2ab'
res = wallet.query_key('mnemonic')
assert res.key == 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
Why this scored 15/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.