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::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<parseNetworkMsgReturn> {
}
#[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 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<createNotificationTransactionReturn> {
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<String, String> = 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(),

View File

@ -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<Option<Label>, HashMap<XOnlyPublicKey, Scalar>>;
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<NotificationInformation> {
) -> 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(