Get the shared secret from a transaction

This commit is contained in:
Sosthene00 2024-04-18 00:36:38 +02:00
parent 0f185c693f
commit b5f3c82192
2 changed files with 31 additions and 28 deletions

View File

@ -1,5 +1,6 @@
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Mutex, OnceLock, PoisonError}; use std::sync::{Mutex, OnceLock, PoisonError};
@ -11,6 +12,7 @@ use sdk_common::crypto::AnkSharedSecret;
use serde_json::Error as SerdeJsonError; use serde_json::Error as SerdeJsonError;
use shamir::SecretData; use shamir::SecretData;
use sp_client::bitcoin::consensus::{deserialize, serialize}; 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::hex::{parse, DisplayHex, FromHex, HexToBytesError};
use sp_client::bitcoin::secp256k1::ecdh::SharedSecret; use sp_client::bitcoin::secp256k1::ecdh::SharedSecret;
use sp_client::bitcoin::secp256k1::{PublicKey, SecretKey}; use sp_client::bitcoin::secp256k1::{PublicKey, SecretKey};
@ -355,9 +357,9 @@ pub fn parse_network_msg(raw: String) -> ApiResult<parseNetworkMsgReturn> {
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn get_outpoints_for_user(pre_id: String) -> ApiResult<outputs_list> { pub fn get_outpoints_for_user() -> ApiResult<outputs_list> {
let connected_users = lock_connected_users()?; 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(), message: "Can't find user".to_owned(),
})?; })?;
Ok(outputs_list(user.get_all_outputs())) Ok(outputs_list(user.get_all_outputs()))
@ -395,26 +397,24 @@ pub struct createNotificationTransactionReturn {
#[wasm_bindgen] #[wasm_bindgen]
pub fn create_notification_transaction( pub fn create_notification_transaction(
user_pre_id: String,
recipient: String, recipient: String,
message: String, message: String,
) -> ApiResult<createNotificationTransactionReturn> { ) -> ApiResult<createNotificationTransactionReturn> {
let sp_address: SilentPaymentAddress = recipient.try_into()?; let sp_address: SilentPaymentAddress = recipient.try_into()?;
let (transaction, notification_information) = let (transaction, shared_point) =
create_transaction_for_address(user_pre_id, sp_address, message)?; 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 // 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 let mut spaddress2secret: HashMap<String, String> = HashMap::new();
.into_iter()
.map(|(address, shared_pubkey)| { spaddress2secret.insert(sp_address.into(), shared_secret.as_byte_array().to_lower_hex_string());
let shared_secret = AnkSharedSecret::new_from_public_key(shared_pubkey);
(address.into(), shared_secret.to_string())
})
.collect();
Ok(createNotificationTransactionReturn { Ok(createNotificationTransactionReturn {
transaction: serialize(&transaction).to_lower_hex_string(), transaction: serialize(&transaction).to_lower_hex_string(),

View File

@ -4,11 +4,11 @@ use anyhow::{Error, Result};
use rand::Rng; use rand::Rng;
use sp_client::bitcoin::policy::DUST_RELAY_TX_FEE; 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::bitcoin::{block, Amount, OutPoint};
use sp_client::silentpayments::sending::SilentPaymentAddress; use sp_client::silentpayments::sending::SilentPaymentAddress;
use sp_client::silentpayments::utils::receiving::calculate_shared_secret; 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::{ use sp_client::{
bitcoin::{ bitcoin::{
secp256k1::{PublicKey, Scalar, XOnlyPublicKey}, secp256k1::{PublicKey, Scalar, XOnlyPublicKey},
@ -21,30 +21,30 @@ use crate::user::{lock_connected_users, CONNECTED_USERS};
type FoundOutputs = HashMap<Option<Label>, HashMap<XOnlyPublicKey, Scalar>>; type FoundOutputs = HashMap<Option<Label>, HashMap<XOnlyPublicKey, Scalar>>;
type NotificationInformation = (Transaction, Vec<(SilentPaymentAddress, PublicKey)>); type SharedPoint = [u8;64];
pub fn create_transaction_for_address( pub fn create_transaction_for_address_with_shared_secret(
send_as: String,
sp_address: SilentPaymentAddress, sp_address: SilentPaymentAddress,
message: String, message: String,
) -> Result<NotificationInformation> { ) -> Result<(Transaction, SharedPoint)> {
let connected_users = lock_connected_users()?; let connected_users = lock_connected_users()?;
let sender = connected_users let (_, wallets) = connected_users
.get(&send_as) .iter()
.last()
.ok_or(Error::msg("Unknown sender"))?; .ok_or(Error::msg("Unknown sender"))?;
let sp_wallet = if sp_address.is_testnet() { let sp_wallet = if sp_address.is_testnet() {
&sender.recover &wallets.recover
} else { } else {
if let Some(main) = &sender.main { if let Some(main) = &wallets.main {
main main
} else { } else {
return Err(Error::msg("Can't spend on mainnet")); 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 // Here we need to add more heuristics about which outpoint we spend
// For now let's keep it simple // For now let's keep it simple
@ -80,8 +80,8 @@ pub fn create_transaction_for_address(
.create_new_psbt(inputs, vec![recipient], None)?; .create_new_psbt(inputs, vec![recipient], None)?;
log::debug!("Created psbt: {}", new_psbt); log::debug!("Created psbt: {}", new_psbt);
SpClient::set_fees(&mut new_psbt, Amount::from_sat(1000), sp_address.into())?; SpClient::set_fees(&mut new_psbt, Amount::from_sat(1000), sp_address.into())?;
let shared_secrets: Vec<(SilentPaymentAddress, PublicKey)> = let partial_secret = sp_wallet.get_client().get_partial_secret_from_psbt(&new_psbt)?;
sp_wallet.get_client().fill_sp_outputs(&mut new_psbt)?; sp_wallet.get_client().fill_sp_outputs(&mut new_psbt, partial_secret)?;
log::debug!("Definitive psbt: {}", new_psbt); log::debug!("Definitive psbt: {}", new_psbt);
let mut aux_rand = [0u8; 32]; let mut aux_rand = [0u8; 32];
rand::thread_rng().fill(&mut aux_rand); rand::thread_rng().fill(&mut aux_rand);
@ -91,7 +91,10 @@ pub fn create_transaction_for_address(
let final_tx = signed.extract_tx()?; 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( pub fn check_transaction(