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::key::{Parity, Secp256k1};
use sdk_common::sp_client::bitcoin::network::ParseNetworkError; 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::psbt::raw;
use sdk_common::sp_client::bitcoin::secp256k1::ecdh::shared_secret_point; use sdk_common::sp_client::bitcoin::secp256k1::ecdh::shared_secret_point;
use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, Scalar, SecretKey}; use sdk_common::sp_client::bitcoin::secp256k1::{PublicKey, Scalar, SecretKey};
@ -46,8 +47,7 @@ use wasm_bindgen::convert::FromWasmAbi;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use sdk_common::network::{ use sdk_common::network::{
self, AnkFlag, AnkNetworkMsg, CachedMessage, CachedMessageStatus, CipherMessage, FaucetMessage, self, AnkFlag, CachedMessage, CachedMessageStatus, Envelope, FaucetMessage, NewTxMessage, Pcd, Prd
NewTxMessage,
}; };
use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address}; 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 (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()); message.commited_in = Some(outpoint.clone());
// freeze the commitment utxo // freeze the commitment utxo
let mut freezed_utxos = lock_freezed_utxos()?; 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.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
message.commitment = Some(commitment_str); message.commitment = Some(commitment_str);
message.plaintext.push(cipher_msg.message);
message.ciphertext = None;
message.sender = Some(cipher_msg.sender); message.sender = Some(cipher_msg.sender);
message.recipient = Some(sp_wallet.get_client().get_receiving_address()); message.recipient = Some(sp_wallet.get_client().get_receiving_address());
message.status = CachedMessageStatus::ReceivedMustConfirm; message.status = CachedMessageStatus::ReceivedMustConfirm;
@ -600,7 +598,7 @@ fn handle_transaction(
new_msg.commitment = Some(commitment.to_lower_hex_string()); new_msg.commitment = Some(commitment.to_lower_hex_string());
new_msg.recipient = Some(sp_wallet.get_client().get_receiving_address()); 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.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()); messages.push(new_msg.clone());
return Ok(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 mut messages = lock_messages()?;
let cipher = Vec::from_hex(&cipher_msg.trim_matches('\"'))?; let cipher = Vec::from_hex(&cipher_msg.trim_matches('\"'))?;
if let Some(message) = messages.iter_mut().find(|m| match m.status { if let Some(message) = messages.iter_mut().find(|m| match m.status {
CachedMessageStatus::TxWaitingCipher | CachedMessageStatus::Trusted => { CachedMessageStatus::TxWaitingPrd => {
m.try_decrypt_cipher(cipher.clone()).is_ok() m.try_decrypt_prd(cipher.clone()).is_ok()
}
CachedMessageStatus::GotPrdWaitingPcd => {
m.try_decrypt_pcd(cipher.clone()).is_ok()
} }
_ => return false, _ => return false,
}) { }) {
let plain = message.try_decrypt_cipher(cipher).unwrap(); if message.status == CachedMessageStatus::TxWaitingPrd {
// debug!("Found message {}", String::from_utf8(plain.clone())?); let plain = message.try_decrypt_prd(cipher).unwrap();
if message.status == CachedMessageStatus::TxWaitingCipher { debug!("Found message {}", String::from_utf8(plain.clone())?);
let cipher_msg: CipherMessage = serde_json::from_slice(&plain)?; let prd: Prd = serde_json::from_slice(&plain)?;
// does the retrieved message match with the commited hash? // 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 { if Some(hash) != message.commitment {
return Err(ApiError { 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.sender = Some(prd.sender.clone());
message.ciphertext = None; message.pcd_commitment = Some(prd.pcd_commitment.to_string());
if cipher_msg.message.starts_with("PAIRING") { 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 // we don't follow the classic confirmation pattern
// if we agree, we must send another notification to remote // if we agree, we must send another notification to remote
// the notification output here will be spent as our first session // the notification output here will be spent as our first session
message.status = CachedMessageStatus::Pairing; message.status = CachedMessageStatus::Pairing;
} else if cipher_msg.message.starts_with("LOGIN") { } else if pcd.message.starts_with("LOGIN") {
message.status = CachedMessageStatus::Login; message.status = CachedMessageStatus::Login;
} else { } else {
message.status = CachedMessageStatus::ReceivedMustConfirm; message.status = CachedMessageStatus::ReceivedMustConfirm;
} }
message.plaintext.push(cipher_msg.message); message.pcd = Some(pcd);
} else { message.pcd_cipher = None;
// 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)?);
} }
return Ok(message.clone()); return Ok(message.clone());
} else { } else {
// let's keep it in case we receive the transaction later // let's keep it in case we receive the transaction later
let mut new_msg = CachedMessage::new(); let mut new_msg = CachedMessage::new();
new_msg.status = CachedMessageStatus::CipherWaitingTx; new_msg.status = CachedMessageStatus::CipherWaitingTx;
new_msg.ciphertext = Some(cipher_msg); new_msg.prd_cipher = Some(cipher_msg);
messages.push(new_msg.clone()); messages.push(new_msg.clone());
return Ok(new_msg); return Ok(new_msg);
} }
@ -851,7 +865,7 @@ pub fn create_confirmation_transaction(
let mut messages = lock_messages()?; let mut messages = lock_messages()?;
let message: &mut CachedMessage; let message: &mut CachedMessage;
if let Some(m) = messages.iter_mut().find(|m| m.id == message_id) { 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 { return Err(ApiError {
message: "Invalid network message".to_owned(), 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 local_device
.get_wallet() .get_wallet()
.get_client() .get_client()
.get_receiving_address(), .get_receiving_address()
"LOGIN".to_owned(), .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(); 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, &freezed_utxos,
sp_wallet, sp_wallet,
vec![recipient], vec![recipient],
Some(Vec::from_hex(&commitment)?), Some(commitment.as_byte_array().to_vec()),
Amount::from_sat(fee_rate.into()), Amount::from_sat(fee_rate.into()),
None, None,
)?; )?;
@ -987,7 +1007,7 @@ pub fn create_login_transaction(fee_rate: u32) -> ApiResult<createTransactionRet
let shared_secret = AnkSharedSecret::new(shared_point); let shared_secret = AnkSharedSecret::new(shared_point);
let cipher = encrypt_with_key( let cipher = encrypt_with_key(
serde_json::to_string(&cipher_msg)?, prd.to_string(),
shared_secret.to_byte_array().to_lower_hex_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 final_tx = signed_psbt.extract_tx()?;
let mut new_msg = CachedMessage::new(); let mut new_msg = CachedMessage::new();
new_msg.plaintext.push(cipher_msg.message); new_msg.sender = Some(prd.sender.clone());
new_msg.ciphertext = Some(cipher); new_msg.pcd = Some(pcd);
new_msg.commitment = Some(commitment); 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 { new_msg.commited_in = Some(OutPoint {
txid: final_tx.txid(), txid: final_tx.txid(),
vout: recipients_vouts[0] as u32, vout: recipients_vouts[0] as u32,
}); });
new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
new_msg.recipient = Some(recipient_address.into()); 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.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself
new_msg.status = CachedMessageStatus::Login; new_msg.status = CachedMessageStatus::Login;
lock_messages()?.push(new_msg.clone()); lock_messages()?.push(new_msg.clone());
@ -1032,9 +1054,9 @@ pub fn create_pairing_transaction(
.get_client() .get_client()
.get_receiving_address(); .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()?; let mut messages = lock_messages()?;
@ -1051,7 +1073,7 @@ pub fn create_pairing_transaction(
#[wasm_bindgen] #[wasm_bindgen]
pub fn create_notification_transaction( pub fn create_notification_transaction(
address: String, address: String,
cipher_message: CipherMessage, pcd: Pcd,
fee_rate: u32, fee_rate: u32,
) -> ApiResult<createTransactionReturn> { ) -> ApiResult<createTransactionReturn> {
let sp_address: SilentPaymentAddress = address.as_str().try_into()?; let sp_address: SilentPaymentAddress = address.as_str().try_into()?;
@ -1066,7 +1088,19 @@ pub fn create_notification_transaction(
nb_outputs: 1, 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()?; let freezed_utxos = lock_freezed_utxos()?;
@ -1075,7 +1109,7 @@ pub fn create_notification_transaction(
&freezed_utxos, &freezed_utxos,
sp_wallet, sp_wallet,
vec![recipient], vec![recipient],
Some(Vec::from_hex(&commitment)?), Some(prd_commitment.as_byte_array().to_vec()),
Amount::from_sat(fee_rate.into()), Amount::from_sat(fee_rate.into()),
None, None,
)?; )?;
@ -1092,7 +1126,7 @@ pub fn create_notification_transaction(
let shared_secret = AnkSharedSecret::new(shared_point); let shared_secret = AnkSharedSecret::new(shared_point);
let cipher = encrypt_with_key( 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(), 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 // for now let's just take the smallest vout that belongs to the recipient
let final_tx = signed_psbt.extract_tx()?; let final_tx = signed_psbt.extract_tx()?;
let mut new_msg = CachedMessage::new(); let mut new_msg = CachedMessage::new();
new_msg.plaintext.push(cipher_message.message); new_msg.sender = Some(prd.sender.clone());
new_msg.ciphertext = Some(cipher); new_msg.prd = Some(prd);
new_msg.commitment = Some(commitment); 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 { new_msg.commited_in = Some(OutPoint {
txid: final_tx.txid(), txid: final_tx.txid(),
vout: recipients_vouts[0] as u32, vout: recipients_vouts[0] as u32,
}); });
new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string()); new_msg.shared_secret = Some(shared_secret.to_byte_array().to_lower_hex_string());
new_msg.recipient = Some(address); 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.tied_by = Some(1); // for now we just assume that's the second utxo, first being the notification itself
new_msg.status = CachedMessageStatus::SentWaitingConfirmation; new_msg.status = CachedMessageStatus::SentWaitingConfirmation;
lock_messages()?.push(new_msg.clone()); lock_messages()?.push(new_msg.clone());
@ -1209,15 +1246,19 @@ pub fn create_faucet_msg() -> ApiResult<String> {
cached_msg.status = CachedMessageStatus::FaucetWaiting; cached_msg.status = CachedMessageStatus::FaucetWaiting;
lock_messages()?.push(cached_msg.clone()); 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()) 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] #[wasm_bindgen]
pub fn create_commitment(payload_to_hash: String) -> String { pub fn create_commitment(payload_to_hash: String) -> String {
let mut engine = sha256::HashEngine::default(); let hash = sha256sum(payload_to_hash.as_bytes());
engine.write_all(&payload_to_hash.as_bytes());
let hash = sha256::Hash::from_engine(engine);
hash.to_byte_array().to_lower_hex_string() hash.to_byte_array().to_lower_hex_string()
} }