spark_sdk/wallet/internal_handlers/implementations/
deposit.rs1use crate::error::SparkSdkError;
2use crate::signer::traits::SparkSigner;
3use crate::wallet::client::SparkSdk;
4use crate::wallet::internal_handlers::traits::deposit::DepositInternalHandlers;
5use crate::wallet::utils::bitcoin::compute_taproot_key_no_script;
6use crate::wallet::utils::ecdsa::verify_operator_ecdsa_signature;
7use crate::wallet::utils::proof_of_possession::proof_of_possession_message_hash_for_deposit_address;
8use sha256;
9use tonic::async_trait;
10
11#[async_trait]
12impl<S: SparkSigner + Send + Sync + Clone + 'static> DepositInternalHandlers<S> for SparkSdk<S> {
13 async fn validate_deposit_address(
14 &self,
15 address: spark_protos::spark::Address,
16 user_pubkey: Vec<u8>,
17 ) -> Result<(), SparkSdkError> {
18 use spark_cryptography::key_arithmetic::subtract_public_keys;
19
20 let deposit_address_proof = match address.deposit_address_proof {
21 Some(deposit_address_proof) => deposit_address_proof,
22 None => {
23 return Err(SparkSdkError::DepositAddressValidationFailed(
24 "Deposit address proof is empty".to_string(),
25 ));
26 }
27 };
28
29 let se_pubkey = subtract_public_keys(&address.verifying_key, &user_pubkey)?;
30
31 let message = proof_of_possession_message_hash_for_deposit_address(
32 &self.get_identity_public_key(),
33 &se_pubkey,
34 address.address.as_bytes(),
35 );
36
37 let sig = bitcoin::secp256k1::schnorr::Signature::from_slice(
38 &deposit_address_proof.proof_of_possession_signature,
39 )?;
40
41 let se_pubkey = bitcoin::secp256k1::PublicKey::from_slice(&se_pubkey)?;
42 let taproot_key = compute_taproot_key_no_script(se_pubkey)?;
43
44 let secp = bitcoin::secp256k1::Secp256k1::new();
45 let verified = secp.verify_schnorr(
46 &sig,
47 &bitcoin::secp256k1::Message::from_digest_slice(&message)?,
48 &taproot_key,
50 );
51
52 if verified.is_err() {
53 return Err(SparkSdkError::DepositAddressValidationFailed(
54 "signature verification failed".to_string(),
55 ));
56 }
57
58 let addr_hash = sha256::digest(address.address.as_bytes());
59 let secp = bitcoin::secp256k1::Secp256k1::verification_only();
60 for operator in self.config.spark_config.spark_operators.iter() {
61 if operator.id == self.config.spark_config.coordinator_index {
62 continue;
63 }
64
65 let operator_sig = deposit_address_proof
66 .address_signatures
67 .get(&operator.frost_identifier)
68 .ok_or_else(|| {
69 SparkSdkError::DepositAddressValidationFailed(format!(
70 "Missing signature for operator {}",
71 operator.frost_identifier
72 ))
73 })?;
74
75 let addr_hash_bytes = hex::decode(&addr_hash).map_err(|e| {
77 SparkSdkError::DepositAddressValidationFailed(format!(
78 "Failed to decode addr_hash: {}",
79 e
80 ))
81 })?;
82
83 verify_operator_ecdsa_signature(
84 operator_sig,
85 &operator.identity_public_key,
86 &addr_hash_bytes,
87 &secp,
88 )?;
89 }
90
91 Ok(())
92 }
93}