From b5f3c821927b25781ca01a0b0a884ca8a19f19b8 Mon Sep 17 00:00:00 2001 From: Sosthene00 <674694@protonmail.ch> Date: Thu, 18 Apr 2024 00:36:38 +0200 Subject: [PATCH] Get the shared secret from a transaction --- crates/sp_client/src/api.rs | 28 +++++++++++------------ crates/sp_client/src/silentpayments.rs | 31 ++++++++++++++------------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/crates/sp_client/src/api.rs b/crates/sp_client/src/api.rs index 0eb9bf7..6046111 100644 --- a/crates/sp_client/src/api.rs +++ b/crates/sp_client/src/api.rs @@ -1,5 +1,6 @@ use std::any::Any; use std::collections::HashMap; +use std::io::Write; use std::str::FromStr; use std::sync::{Mutex, OnceLock, PoisonError}; @@ -11,6 +12,7 @@ use sdk_common::crypto::AnkSharedSecret; use serde_json::Error as SerdeJsonError; use shamir::SecretData; use sp_client::bitcoin::consensus::{deserialize, serialize}; +use sp_client::silentpayments::bitcoin_hashes::{HashEngine, sha256, Hash}; use sp_client::bitcoin::hex::{parse, DisplayHex, FromHex, HexToBytesError}; use sp_client::bitcoin::secp256k1::ecdh::SharedSecret; use sp_client::bitcoin::secp256k1::{PublicKey, SecretKey}; @@ -355,9 +357,9 @@ pub fn parse_network_msg(raw: String) -> ApiResult { } #[wasm_bindgen] -pub fn get_outpoints_for_user(pre_id: String) -> ApiResult { +pub fn get_outpoints_for_user() -> ApiResult { let connected_users = lock_connected_users()?; - let user = connected_users.get(&pre_id).ok_or(ApiError { + let (_, user) = connected_users.iter().last().ok_or(ApiError { message: "Can't find user".to_owned(), })?; Ok(outputs_list(user.get_all_outputs())) @@ -395,26 +397,24 @@ pub struct createNotificationTransactionReturn { #[wasm_bindgen] pub fn create_notification_transaction( - user_pre_id: String, recipient: String, message: String, ) -> ApiResult { let sp_address: SilentPaymentAddress = recipient.try_into()?; - let (transaction, notification_information) = - create_transaction_for_address(user_pre_id, sp_address, message)?; + let (transaction, shared_point) = + create_transaction_for_address_with_shared_secret(sp_address, message)?; - // The secret is an ecc point and *must* be hashed to produce a proper ecdh secret + // The shared_point *must* be hashed to produce a proper ecdh secret // For now we propose to implement a tagged hash for it - // It could be interesting to add some piece of data to allow for the derivation of multiple secrets + // It could be interesting to add some piece of data to allow for the derivation of multiple secrets + let mut eng = sha256::HashEngine::default(); + eng.write_all(&shared_point); + let shared_secret = sha256::Hash::from_engine(eng); - let spaddress2secret = notification_information - .into_iter() - .map(|(address, shared_pubkey)| { - let shared_secret = AnkSharedSecret::new_from_public_key(shared_pubkey); - (address.into(), shared_secret.to_string()) - }) - .collect(); + let mut spaddress2secret: HashMap = HashMap::new(); + + spaddress2secret.insert(sp_address.into(), shared_secret.as_byte_array().to_lower_hex_string()); Ok(createNotificationTransactionReturn { transaction: serialize(&transaction).to_lower_hex_string(), diff --git a/crates/sp_client/src/silentpayments.rs b/crates/sp_client/src/silentpayments.rs index a82f99e..ac2a223 100644 --- a/crates/sp_client/src/silentpayments.rs +++ b/crates/sp_client/src/silentpayments.rs @@ -4,11 +4,11 @@ use anyhow::{Error, Result}; use rand::Rng; use sp_client::bitcoin::policy::DUST_RELAY_TX_FEE; -use sp_client::bitcoin::secp256k1::ecdh::SharedSecret; +use sp_client::bitcoin::secp256k1::ecdh::shared_secret_point; use sp_client::bitcoin::{block, Amount, OutPoint}; use sp_client::silentpayments::sending::SilentPaymentAddress; use sp_client::silentpayments::utils::receiving::calculate_shared_secret; -use sp_client::spclient::{OutputList, OwnedOutput, Recipient, SpClient}; +use sp_client::spclient::{OutputList, OwnedOutput, Recipient, SpClient, SpWallet}; use sp_client::{ bitcoin::{ secp256k1::{PublicKey, Scalar, XOnlyPublicKey}, @@ -21,30 +21,30 @@ use crate::user::{lock_connected_users, CONNECTED_USERS}; type FoundOutputs = HashMap, HashMap>; -type NotificationInformation = (Transaction, Vec<(SilentPaymentAddress, PublicKey)>); +type SharedPoint = [u8;64]; -pub fn create_transaction_for_address( - send_as: String, +pub fn create_transaction_for_address_with_shared_secret( sp_address: SilentPaymentAddress, message: String, -) -> Result { +) -> Result<(Transaction, SharedPoint)> { let connected_users = lock_connected_users()?; - let sender = connected_users - .get(&send_as) + let (_, wallets) = connected_users + .iter() + .last() .ok_or(Error::msg("Unknown sender"))?; let sp_wallet = if sp_address.is_testnet() { - &sender.recover + &wallets.recover } else { - if let Some(main) = &sender.main { + if let Some(main) = &wallets.main { main } else { return Err(Error::msg("Can't spend on mainnet")); } }; - let available_outpoints = sender.recover.get_outputs().to_spendable_list(); + let available_outpoints = wallets.recover.get_outputs().to_spendable_list(); // Here we need to add more heuristics about which outpoint we spend // For now let's keep it simple @@ -80,8 +80,8 @@ pub fn create_transaction_for_address( .create_new_psbt(inputs, vec![recipient], None)?; log::debug!("Created psbt: {}", new_psbt); SpClient::set_fees(&mut new_psbt, Amount::from_sat(1000), sp_address.into())?; - let shared_secrets: Vec<(SilentPaymentAddress, PublicKey)> = - sp_wallet.get_client().fill_sp_outputs(&mut new_psbt)?; + let partial_secret = sp_wallet.get_client().get_partial_secret_from_psbt(&new_psbt)?; + sp_wallet.get_client().fill_sp_outputs(&mut new_psbt, partial_secret)?; log::debug!("Definitive psbt: {}", new_psbt); let mut aux_rand = [0u8; 32]; rand::thread_rng().fill(&mut aux_rand); @@ -91,7 +91,10 @@ pub fn create_transaction_for_address( let final_tx = signed.extract_tx()?; - Ok((final_tx, shared_secrets)) + // This should not be directly used without hashing + let shared_point = shared_secret_point(&sp_address.get_scan_key(), &partial_secret); + + Ok((final_tx, shared_point)) } pub fn check_transaction(