From d2842831cb4b721ce5eca373135128e5e0b6eb21 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Thu, 4 Sep 2025 04:50:52 +0200 Subject: [PATCH] Refactor prd connect logic --- src/api.rs | 62 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/api.rs b/src/api.rs index 68d6928..a550b53 100644 --- a/src/api.rs +++ b/src/api.rs @@ -574,13 +574,11 @@ fn handle_transaction( public_data: PublicKey, ) -> AnyhowResult { let b_scan: SecretKey; - let local_member: Member; let sp_wallet: SpClient; { let local_device = lock_local_device()?; sp_wallet = local_device.get_sp_client().clone(); b_scan = local_device.get_sp_client().get_scan_key(); - local_member = local_device.to_member(); } // Basically a transaction that destroyed utxo is a transaction we sent. @@ -610,7 +608,7 @@ fn handle_transaction( let secret_hash = AnkMessageHash::from_message(shared_secret.as_byte_array()); // We still don't know who sent it, so we reply with a `Connect` prd - let prd_connect = Prd::new_connect(local_member, secret_hash, None); + let prd_connect = Prd::new_connect(None, secret_hash, None); let msg = prd_connect.to_network_msg(&sp_wallet)?; @@ -741,54 +739,64 @@ fn create_diffs(device: &MutexGuard, process: &Process, new_state: &Proc Ok(diffs) } -fn handle_prd_connect(prd: Prd, secret: AnkSharedSecretHash) -> AnyhowResult { +fn handle_prd_connect(prd: Prd, secret: AnkSharedSecretHash, members_list: &OutPointMemberMap) -> AnyhowResult { let local_device = lock_local_device()?; - let local_member = local_device.to_member(); + let local_address = local_device.get_address(); let sp_wallet = local_device.get_sp_client(); let secret_hash = AnkMessageHash::from_message(secret.as_byte_array()); let mut shared_secrets = lock_shared_secrets()?; if let Some(prev_proof) = prd.validation_tokens.get(0) { + // We are receiving this as an answer to a prd connect we sent + if prd.proof.is_none() { + return Err(anyhow::Error::msg("Missing proof")); + } + // check that the proof is valid prev_proof.verify()?; // Check it's signed with our key - let local_address = SilentPaymentAddress::try_from(sp_wallet.get_receiving_address())?; if prev_proof.get_key() != local_address.get_spend_key() { return Err(anyhow::Error::msg("Previous proof of a prd connect isn't signed by us")); } + // Check it signs a prd connect that contains the commitment to the shared secret - let empty_prd = Prd::new_connect(local_member, secret_hash, None); + let empty_prd = Prd::new_connect(None, secret_hash, None); let msg = AnkMessageHash::from_message(empty_prd.to_string().as_bytes()); if *msg.as_byte_array() != prev_proof.get_message() { return Err(anyhow::Error::msg("Previous proof signs another message")); } - // Now we can confirm the secret and link it to an address - let proof = prd.proof.unwrap(); - let actual_sender = prd.sender.get_address_for_key(&proof.get_key()) - .ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?; - shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?); - let mut secrets_return = SecretsStore::new(); - secrets_return.confirm_secret_for_address(secret, actual_sender.try_into()?); - return Ok(ApiReturn { - secrets: Some(secrets_return), - ..Default::default() - }) + + // If sender provided its pairing id we can confirm the secret and link it to an address + if prd.sender.is_some() { + let actual_sender = members_list.0.get(&prd.sender.unwrap()).ok_or(anyhow::Error::msg("Sender not found"))?.get_address_for_key(&prd.proof.unwrap().get_key()) + .ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?; + shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?); + let mut secrets_return = SecretsStore::new(); + secrets_return.confirm_secret_for_address(secret, actual_sender.try_into()?); + return Ok(ApiReturn { + secrets: Some(secrets_return), + ..Default::default() + }) + } else { + // otherwise we can't confirm the secret so we just do nothing + return Ok(ApiReturn::default()); + } } else { - let proof = prd.proof.unwrap(); - let actual_sender = prd.sender.get_address_for_key(&proof.get_key()) - .ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?; + // We sent a transaction to some address and they answer with a prd connect + if prd.proof.is_none() { + return Err(anyhow::Error::msg("Missing proof")); + } - shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?); + // TODO check that the key in the proof match what we have in the secret store - let mut secrets_return = SecretsStore::new(); - secrets_return.confirm_secret_for_address(secret, actual_sender.try_into()?); + let sender = local_device.get_pairing_commitment(); - let prd_connect = Prd::new_connect(local_member, secret_hash, prd.proof); + // We create a prd connect with their own proof in validation tokens so that they can be sure who they're sharing the secret with + let prd_connect = Prd::new_connect(sender, secret_hash, prd.proof); let msg = prd_connect.to_network_msg(sp_wallet)?; let cipher = encrypt_with_key(secret.as_byte_array(), msg.as_bytes())?; return Ok(ApiReturn { ciphers_to_send: vec![cipher.to_lower_hex_string()], - secrets: Some(secrets_return), ..Default::default() }) } @@ -804,7 +812,7 @@ fn handle_prd( // Connect is a bit different here because there's no associated process // Let's handle that case separately if prd.prd_type == PrdType::Connect { - return handle_prd_connect(prd, secret); + return handle_prd_connect(prd, secret, members_list); } let outpoint = prd.process_id;