Update api

This commit is contained in:
Sosthene 2024-08-15 16:19:11 +02:00
parent b2cab53188
commit 361a8aa409

View File

@ -23,6 +23,7 @@ use sdk_common::sp_client::bitcoin::hex::{
};
use sdk_common::sp_client::bitcoin::key::{Parity, Secp256k1};
use sdk_common::sp_client::bitcoin::network::ParseNetworkError;
use sdk_common::sp_client::bitcoin::p2p::message::NetworkMessage;
use sdk_common::sp_client::bitcoin::psbt::raw;
use sdk_common::sp_client::bitcoin::secp256k1::ecdh::shared_secret_point;
use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, Scalar, SecretKey};
@ -46,8 +47,7 @@ use wasm_bindgen::convert::FromWasmAbi;
use wasm_bindgen::prelude::*;
use sdk_common::network::{
self, AnkFlag, AnkNetworkMsg, CachedMessage, CachedMessageStatus, CipherMessage, FaucetMessage,
NewTxMessage,
self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage, Pcd, Prd
};
use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address};
@ -570,7 +570,7 @@ fn handle_transaction(
}) {
let (outpoint, output) = utxo_created.into_iter().next().unwrap();
let cipher_msg: CipherMessage = serde_json::from_slice(&plaintext)?;
let cipher_msg: Prd = serde_json::from_slice(&plaintext)?;
message.commited_in = Some(outpoint.clone());
// freeze the commitment utxo
let mut freezed_utxos = lock_freezed_utxos()?;
@ -578,8 +578,6 @@ fn handle_transaction(
message.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
message.commitment = Some(commitment_str);
message.plaintext.push(cipher_msg.message);
message.ciphertext = None;
message.sender = Some(cipher_msg.sender);
message.recipient = Some(sp_wallet.get_client().get_receiving_address());
message.status = CachedMessageStatus::ReceivedMustConfirm;
@ -600,7 +598,7 @@ fn handle_transaction(
new_msg.commitment = Some(commitment.to_lower_hex_string());
new_msg.recipient = Some(sp_wallet.get_client().get_receiving_address());
new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
new_msg.status = CachedMessageStatus::TxWaitingCipher;
new_msg.status = CachedMessageStatus::TxWaitingPrd;
messages.push(new_msg.clone());
return Ok(new_msg.clone());
}
@ -711,46 +709,62 @@ pub fn parse_cipher(cipher_msg: String, fee_rate: u32) -> ApiResult<CachedMessag
let mut messages = lock_messages()?;
let cipher = Vec::from_hex(&cipher_msg.trim_matches('\"'))?;
if let Some(message) = messages.iter_mut().find(|m| match m.status {
CachedMessageStatus::TxWaitingCipher | CachedMessageStatus::Trusted => {
m.try_decrypt_cipher(cipher.clone()).is_ok()
CachedMessageStatus::TxWaitingPrd => {
m.try_decrypt_prd(cipher.clone()).is_ok()
}
CachedMessageStatus::GotPrdWaitingPcd => {
m.try_decrypt_pcd(cipher.clone()).is_ok()
}
_ => return false,
}) {
let plain = message.try_decrypt_cipher(cipher).unwrap();
// debug!("Found message {}", String::from_utf8(plain.clone())?);
if message.status == CachedMessageStatus::TxWaitingCipher {
let cipher_msg: CipherMessage = serde_json::from_slice(&plain)?;
if message.status == CachedMessageStatus::TxWaitingPrd {
let plain = message.try_decrypt_prd(cipher).unwrap();
debug!("Found message {}", String::from_utf8(plain.clone())?);
let prd: Prd = serde_json::from_slice(&plain)?;
// does the retrieved message match with the commited hash?
let hash = create_commitment(serde_json::to_string(&cipher_msg)?);
let hash = create_commitment(serde_json::to_string(&prd)?);
if Some(hash) != message.commitment {
return Err(ApiError {
message: "Message doesn't match commitment".to_owned(),
message: "Prd doesn't match commitment".to_owned(),
});
}
message.sender = Some(cipher_msg.sender);
message.ciphertext = None;
if cipher_msg.message.starts_with("PAIRING") {
message.sender = Some(prd.sender.clone());
message.pcd_commitment = Some(prd.pcd_commitment.to_string());
message.prd_cipher = None;
message.prd = Some(prd);
message.status = CachedMessageStatus::GotPrdWaitingPcd;
} else {
let plain = message.try_decrypt_pcd(cipher).unwrap();
debug!("Found message {}", String::from_utf8(plain.clone())?);
// we're receiving a pcd for a prd we already have
let pcd: Pcd = serde_json::from_slice(&plain)?;
// check that the hash of the pcd is the same than commited in the prd
let pcd_commitment = create_commitment(pcd.to_string());
if Some(&pcd_commitment) != message.pcd_commitment.as_ref() {
return Err(ApiError {
message: format!("Pcd doesn't match commitment: expected {:?}\ngot {}", message.pcd_commitment.as_ref(), pcd_commitment),
});
}
if pcd.message.starts_with("PAIRING") {
// we don't follow the classic confirmation pattern
// if we agree, we must send another notification to remote
// the notification output here will be spent as our first session
message.status = CachedMessageStatus::Pairing;
} else if cipher_msg.message.starts_with("LOGIN") {
} else if pcd.message.starts_with("LOGIN") {
message.status = CachedMessageStatus::Login;
} else {
message.status = CachedMessageStatus::ReceivedMustConfirm;
}
message.plaintext.push(cipher_msg.message);
} else {
// We're receiving a message for some action already engaged
// Let's update the message by pushing what we just found out
message.plaintext.push(String::from_utf8(plain)?);
message.pcd = Some(pcd);
message.pcd_cipher = None;
}
return Ok(message.clone());
} else {
// let's keep it in case we receive the transaction later
let mut new_msg = CachedMessage::new();
new_msg.status = CachedMessageStatus::CipherWaitingTx;
new_msg.ciphertext = Some(cipher_msg);
new_msg.prd_cipher = Some(cipher_msg);
messages.push(new_msg.clone());
return Ok(new_msg);
}
@ -851,7 +865,7 @@ pub fn create_confirmation_transaction(
let mut messages = lock_messages()?;
let message: &mut CachedMessage;
if let Some(m) = messages.iter_mut().find(|m| m.id == message_id) {
if m.sender.is_none() || m.commited_in.is_none() || m.plaintext.is_empty() {
if m.sender.is_none() || m.commited_in.is_none() || m.prd.is_none() {
return Err(ApiError {
message: "Invalid network message".to_owned(),
});
@ -938,19 +952,25 @@ pub fn create_login_transaction(fee_rate: u32) -> ApiResult<createTransactionRet
);
}
debug!("outpoint_to_spend: {}", outpoint_to_spend);
let pcd = Pcd::new("LOGIN".to_owned());
let pcd_commitment = sha256sum(pcd.to_string().as_bytes());
debug!("outputs: {:?}", sp_wallet.get_outputs().to_outpoints_list());
let key: [u8; 32] = Aes256Gcm::generate_key(thread_rng()).into();
let cipher_msg = CipherMessage::new(
let prd = Prd::new(
local_device
.get_wallet()
.get_client()
.get_receiving_address(),
"LOGIN".to_owned(),
.get_receiving_address()
.try_into()
.unwrap(),
key,
pcd_commitment,
);
let commitment = create_commitment(serde_json::to_string(&cipher_msg)?);
let pcd_cipher = prd.encrypt_pcd(&pcd)?;
let commitment = sha256sum(prd.to_string().as_bytes());
let recipient_address = SilentPaymentAddress::try_from(paired_device.address.as_str()).unwrap();
@ -970,7 +990,7 @@ pub fn create_login_transaction(fee_rate: u32) -> ApiResult<createTransactionRet
&freezed_utxos,
sp_wallet,
vec![recipient],
Some(Vec::from_hex(&commitment)?),
Some(commitment.as_byte_array().to_vec()),
Amount::from_sat(fee_rate.into()),
None,
)?;
@ -987,7 +1007,7 @@ pub fn create_login_transaction(fee_rate: u32) -> ApiResult<createTransactionRet
let shared_secret = AnkSharedSecret::new(shared_point);
let cipher = encrypt_with_key(
serde_json::to_string(&cipher_msg)?,
prd.to_string(),
shared_secret.to_byte_array().to_lower_hex_string(),
)?;
@ -1001,16 +1021,18 @@ pub fn create_login_transaction(fee_rate: u32) -> ApiResult<createTransactionRet
let final_tx = signed_psbt.extract_tx()?;
let mut new_msg = CachedMessage::new();
new_msg.plaintext.push(cipher_msg.message);
new_msg.ciphertext = Some(cipher);
new_msg.commitment = Some(commitment);
new_msg.sender = Some(prd.sender.clone());
new_msg.pcd = Some(pcd);
new_msg.pcd_cipher = Some(pcd_cipher.to_lower_hex_string());
new_msg.prd = Some(prd);
new_msg.prd_cipher = Some(cipher);
new_msg.commitment = Some(commitment.to_string());
new_msg.commited_in = Some(OutPoint {
txid: final_tx.txid(),
vout: recipients_vouts[0] as u32,
});
new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
new_msg.recipient = Some(recipient_address.into());
new_msg.sender = Some(cipher_msg.sender);
new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself
new_msg.status = CachedMessageStatus::Login;
lock_messages()?.push(new_msg.clone());
@ -1032,9 +1054,9 @@ pub fn create_pairing_transaction(
.get_client()
.get_receiving_address();
let cipher_message = CipherMessage::new(my_address, "PAIRING".to_owned());
let pcd = Pcd::new("PAIRING".to_owned());
let mut res = create_notification_transaction(address, cipher_message, fee_rate)?;
let mut res = create_notification_transaction(address, pcd, fee_rate)?;
let mut messages = lock_messages()?;
@ -1051,7 +1073,7 @@ pub fn create_pairing_transaction(
#[wasm_bindgen]
pub fn create_notification_transaction(
address: String,
cipher_message: CipherMessage,
pcd: Pcd,
fee_rate: u32,
) -> ApiResult<createTransactionReturn> {
let sp_address: SilentPaymentAddress = address.as_str().try_into()?;
@ -1066,7 +1088,19 @@ pub fn create_notification_transaction(
nb_outputs: 1,
};
let commitment = create_commitment(serde_json::to_string(&cipher_message)?);
let pcd_commitment = sha256sum(pcd.to_string().as_bytes());
let key: [u8; 32] = Aes256Gcm::generate_key(thread_rng()).into();
let prd = Prd::new(
sp_wallet.get_client().get_receiving_address().try_into().unwrap(),
key,
pcd_commitment
);
let prd_commitment = sha256sum(prd.to_string().as_bytes());
let pcd_cipher = prd.encrypt_pcd(&pcd)?;
let freezed_utxos = lock_freezed_utxos()?;
@ -1075,7 +1109,7 @@ pub fn create_notification_transaction(
&freezed_utxos,
sp_wallet,
vec![recipient],
Some(Vec::from_hex(&commitment)?),
Some(prd_commitment.as_byte_array().to_vec()),
Amount::from_sat(fee_rate.into()),
None,
)?;
@ -1092,7 +1126,7 @@ pub fn create_notification_transaction(
let shared_secret = AnkSharedSecret::new(shared_point);
let cipher = encrypt_with_key(
serde_json::to_string(&cipher_message)?,
serde_json::to_string(&prd)?,
shared_secret.to_byte_array().to_lower_hex_string(),
)?;
@ -1105,16 +1139,19 @@ pub fn create_notification_transaction(
// for now let's just take the smallest vout that belongs to the recipient
let final_tx = signed_psbt.extract_tx()?;
let mut new_msg = CachedMessage::new();
new_msg.plaintext.push(cipher_message.message);
new_msg.ciphertext = Some(cipher);
new_msg.commitment = Some(commitment);
new_msg.sender = Some(prd.sender.clone());
new_msg.prd = Some(prd);
new_msg.prd_cipher = Some(cipher);
new_msg.pcd = Some(pcd);
new_msg.pcd_cipher = Some(pcd_cipher.to_lower_hex_string());
new_msg.commitment = Some(prd_commitment.as_byte_array().to_lower_hex_string());
new_msg.commited_in = Some(OutPoint {
txid: final_tx.txid(),
vout: recipients_vouts[0] as u32,
});
new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
new_msg.recipient = Some(address);
new_msg.sender = Some(cipher_message.sender);
new_msg.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself
new_msg.status = CachedMessageStatus::SentWaitingConfirmation;
lock_messages()?.push(new_msg.clone());
@ -1209,15 +1246,19 @@ pub fn create_faucet_msg() -> ApiResult<String> {
cached_msg.status = CachedMessageStatus::FaucetWaiting;
lock_messages()?.push(cached_msg.clone());
let network_msg = AnkNetworkMsg::new(AnkFlag::Faucet, &faucet_msg.to_string());
let network_msg = Envelope::new(AnkFlag::Faucet, &faucet_msg.to_string());
Ok(network_msg.to_string())
}
fn sha256sum(input: &[u8]) -> sha256::Hash {
let mut engine = sha256::HashEngine::default();
engine.write_all(&input);
sha256::Hash::from_engine(engine)
}
#[wasm_bindgen]
pub fn create_commitment(payload_to_hash: String) -> String {
let mut engine = sha256::HashEngine::default();
engine.write_all(&payload_to_hash.as_bytes());
let hash = sha256::Hash::from_engine(engine);
let hash = sha256sum(payload_to_hash.as_bytes());
hash.to_byte_array().to_lower_hex_string()
}