Skip to content

Commit

Permalink
mobilecoind: add tx_out_view_key_match api
Browse files Browse the repository at this point in the history
  • Loading branch information
eranrund committed Nov 8, 2024
1 parent c18a291 commit 58fe140
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
20 changes: 20 additions & 0 deletions mobilecoind/api/proto/mobilecoind_api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ service MobilecoindAPI {
rpc GetPublicAddress (GetPublicAddressRequest) returns (GetPublicAddressResponse) {}
rpc GetShortAddressHash (GetShortAddressHashRequest) returns (GetShortAddressHashResponse) {}
rpc ValidateAuthenticatedSenderMemo (ValidateAuthenticatedSenderMemoRequest) returns (ValidateAuthenticatedSenderMemoResponse) {}
rpc TxOutViewKeyMatch (TxOutViewKeyMatchRequest) returns (TxOutViewKeyMatchResponse) {}

// b58 Codes
rpc ParseRequestCode (ParseRequestCodeRequest) returns (ParseRequestCodeResponse) {}
Expand Down Expand Up @@ -509,6 +510,25 @@ message ValidateAuthenticatedSenderMemoResponse {
bool success = 1;
}

message TxOutViewKeyMatchRequest {
external.TxOut txo = 1;
external.RistrettoPrivate view_private_key = 2;
}

message TxOutViewKeyMatchResponse {
// Whether the tx out belongs to the provided view private key.
bool matched = 1;

// The value of the tx out, only valid if matched is true.
uint64 value = 2;

// The token_id of the tx out, only valid if matched is true.
uint64 token_id = 3;

// The tx out shared secret, only valid if matched is true.
external.CompressedRistretto shared_secret = 4;
}

//
// b58 Codes
//
Expand Down
94 changes: 93 additions & 1 deletion mobilecoind/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use mc_common::{
};
use mc_connection::{BlockInfo, BlockchainConnection, UserTxConnection};
use mc_core::slip10::Slip10KeyGenerator;
use mc_crypto_keys::{CompressedRistrettoPublic, RistrettoPublic};
use mc_crypto_keys::{CompressedRistrettoPublic, RistrettoPrivate, RistrettoPublic};
use mc_fog_report_validation::FogPubkeyResolver;
use mc_ledger_db::{Error as LedgerError, Ledger, LedgerDB};
use mc_ledger_sync::{NetworkState, PollingNetworkState};
Expand Down Expand Up @@ -584,6 +584,34 @@ impl<T: BlockchainConnection + UserTxConnection + 'static, FPR: FogPubkeyResolve
Ok(response)
}

fn tx_out_view_key_match_impl(
&mut self,
request: api::TxOutViewKeyMatchRequest,
) -> Result<api::TxOutViewKeyMatchResponse, RpcStatus> {
let tx_out = TxOut::try_from(request.get_txo())
.map_err(|err| rpc_internal_error("tx_out.try_from", err, &self.logger))?;
let view_private_key = RistrettoPrivate::try_from(request.get_view_private_key())
.map_err(|err| rpc_invalid_arg_error("view_private_key.try_from", err, &self.logger))?;

match tx_out.view_key_match(&view_private_key) {
Ok((amount, shared_secret)) => {
let shared_secret: mc_api::external::CompressedRistretto = (&shared_secret).into();

Ok(api::TxOutViewKeyMatchResponse {
matched: true,
value: amount.value,
token_id: *amount.token_id,
shared_secret: Some(shared_secret).into(),
..Default::default()
})
}
Err(_) => Ok(api::TxOutViewKeyMatchResponse {
matched: false,
..Default::default()
}),
}
}

fn parse_request_code_impl(
&mut self,
request: api::ParseRequestCodeRequest,
Expand Down Expand Up @@ -2626,6 +2654,7 @@ build_api! {
get_public_address GetPublicAddressRequest GetPublicAddressResponse get_public_address_impl,
get_short_address_hash GetShortAddressHashRequest GetShortAddressHashResponse get_short_address_hash_impl,
validate_authenticated_sender_memo ValidateAuthenticatedSenderMemoRequest ValidateAuthenticatedSenderMemoResponse validate_authenticated_sender_memo_impl,
tx_out_view_key_match TxOutViewKeyMatchRequest TxOutViewKeyMatchResponse tx_out_view_key_match_impl,

// b58 codes
parse_request_code ParseRequestCodeRequest ParseRequestCodeResponse parse_request_code_impl,
Expand Down Expand Up @@ -3505,6 +3534,69 @@ mod test {
assert!(!response.success);
}

#[test_with_logger]
fn test_tx_out_view_key_match_impl(logger: Logger) {
let mut rng: StdRng = SeedableRng::from_seed([23u8; 32]);

// no known recipient, 3 random recipients and no monitors.
let (mut ledger_db, _mobilecoind_db, client, _server, _server_conn_manager) =
get_testing_environment(BLOCK_VERSION, 3, &[], &[], logger, &mut rng);

// Insert a block with a known recipient (this is block 4)
let recipient = AccountKey::random(&mut rng);
add_block_to_ledger(
&mut ledger_db,
BLOCK_VERSION,
&[recipient.default_subaddress()],
Amount::new(102030, TokenId::from(1)),
&[KeyImage::from(101)],
&mut rng,
)
.unwrap();

// Get the block so we can test the matching.
let block = client
.get_block(&api::GetBlockRequest {
block: ledger_db.num_blocks().unwrap() - 1,
..Default::default()
})
.unwrap();

// The block should have a single tx out and we should be able to match it with
// the correct view private key.
let view_private_key =
mc_api::external::RistrettoPrivate::from(recipient.view_private_key());
let resp = client
.tx_out_view_key_match(&api::TxOutViewKeyMatchRequest {
txo: Some(block.txos[0].clone()).into(),
view_private_key: Some(view_private_key).into(),
..Default::default()
})
.unwrap();

assert_eq!(resp.matched, true);
assert_eq!(resp.value, 102030);
assert_eq!(resp.token_id, 1);
assert_eq!(resp.get_shared_secret().data.len(), 32);

// Try with an incorrect view private key
let view_private_key = mc_api::external::RistrettoPrivate::from(
AccountKey::random(&mut rng).view_private_key(),
);
let resp = client
.tx_out_view_key_match(&api::TxOutViewKeyMatchRequest {
txo: Some(block.txos[0].clone()).into(),
view_private_key: Some(view_private_key).into(),
..Default::default()
})
.unwrap();

assert_eq!(resp.matched, false);
assert_eq!(resp.value, 0);
assert_eq!(resp.token_id, 0);
assert_eq!(resp.get_shared_secret().data.len(), 0);
}

#[test_with_logger]
fn test_vectors_validate_authenticated_sender_memo_impl(logger: Logger) {
// In this test, we take an actual TxOut generated by signal, at block version
Expand Down

0 comments on commit 58fe140

Please sign in to comment.